/home/liu/actions-runner/_work/ccv/ccv/test/case_main.h
Line | Count | Source (jump to first uncovered line) |
1 | | #if !defined(_GUARD_case_main_h_) && !defined(CASE_DISABLE_MAIN) |
2 | | #define _GUARD_case_main_h_ |
3 | | |
4 | | #include <string.h> |
5 | | #include <assert.h> |
6 | | |
7 | | static int case_print_hi(char* str, const char* const hi) |
8 | 0 | { |
9 | 0 | if (!hi) |
10 | 0 | return printf("%s", str); |
11 | 0 | const size_t hilen = strlen(hi); |
12 | 0 | char* savestr = strstr(str, hi); |
13 | 0 | int nchr = 0; |
14 | 0 | while (savestr) |
15 | 0 | { |
16 | 0 | for (;str < savestr; ++str, ++nchr) |
17 | 0 | putchar(str[0]); |
18 | 0 | nchr += printf("\033[7m%s\033[0m", hi); // decorate with underline. |
19 | 0 | str += hilen; |
20 | 0 | savestr = strstr(str, hi); |
21 | 0 | } |
22 | 0 | nchr += printf("%s", str); |
23 | 0 | return nchr; |
24 | 0 | } |
25 | | |
26 | | static void case_run(case_t* test_case, const char* const match_test, int i, int total, int* pass, int* skip, int* fail) |
27 | 1.08k | { |
28 | | // Change the current directory. |
29 | 1.08k | if (test_case->dir && test_case->dir[0] != 0 && strcmp(test_case->dir, ".") != 0) |
30 | 1.08k | chdir(test_case->dir); |
31 | 1.08k | int clr = 0; |
32 | 1.08k | if (isatty(fileno(stdout))) |
33 | 0 | { |
34 | 0 | clr += printf("\033[0;34m[%d/%d]\033[0;0m \033[1;33m[RUN]\033[0;0m ", i + 1, total); |
35 | 0 | clr += case_print_hi(test_case->name, match_test); |
36 | 0 | clr += printf(" ..."); |
37 | 0 | } else |
38 | 1.08k | clr += printf("[%d/%d] [RUN] %s ...", i + 1, total, test_case->name); |
39 | 1.08k | fflush(stdout); |
40 | 1.08k | int result = 0; |
41 | 1.08k | test_case->func(test_case->name, &result); |
42 | 1.08k | if (result == 0) |
43 | 937 | { |
44 | 937 | (*pass)++; |
45 | 63.1k | for (; clr > 0; --clr62.2k ) |
46 | 62.2k | printf("\b"); |
47 | 937 | if (isatty(fileno(stdout))) |
48 | 0 | { |
49 | 0 | printf("\r\033[0;34m[%d/%d]\033[0;0m \033[1;32m[PASS]\033[0;0m ", i + 1, total); |
50 | 0 | case_print_hi(test_case->name, match_test); |
51 | 0 | printf(" \n"); |
52 | 0 | } else |
53 | 937 | printf("\r[%d/%d] [PASS] %s \n", i + 1, total, test_case->name); |
54 | 937 | } else if (147 result == -2147 ) { |
55 | 147 | (*skip)++; |
56 | 147 | if (isatty(fileno(stdout))) |
57 | 0 | { |
58 | 0 | printf("\n\033[0;34m[%d/%d]\033[0;0m \033[1;32m[SKIP]\033[0;0m ", i + 1, total); |
59 | 0 | case_print_hi(test_case->name, match_test); |
60 | 0 | printf("\n"); |
61 | 0 | } else |
62 | 147 | printf("\n[%d/%d] [SKIP] %s\n", i + 1, total, test_case->name); |
63 | 147 | } else { |
64 | 0 | (*fail)++; |
65 | 0 | if (isatty(fileno(stdout))) |
66 | 0 | { |
67 | 0 | printf("\n\033[0;34m[%d/%d]\033[0;0m \033[1;31m[FAIL]\033[0;0m ", i + 1, total); |
68 | 0 | case_print_hi(test_case->name, match_test); |
69 | 0 | printf("\n"); |
70 | 0 | } else |
71 | 0 | printf("\n[%d/%d] [FAIL] %s\n", i + 1, total, test_case->name); |
72 | 0 | } |
73 | 1.08k | } |
74 | | |
75 | | static void case_conclude(int pass, int skip, int fail) |
76 | 1 | { |
77 | 1 | if (isatty(fileno(stdout))) |
78 | 0 | { |
79 | 0 | if (skip > 0) |
80 | 0 | { |
81 | 0 | if (fail == 0) |
82 | 0 | printf("\033[0;32mall test case(s) passed, %d test case(s) skipped, congratulations!\033[0;0m\n", skip); |
83 | 0 | else |
84 | 0 | printf("\033[0;31m%d of %d test case(s) passed, %d test case(s) skipped\033[0;0m\n", pass, fail + pass, skip); |
85 | 0 | } else { |
86 | 0 | if (fail == 0) |
87 | 0 | printf("\033[0;32mall test case(s) passed, congratulations!\033[0;0m\n"); |
88 | 0 | else |
89 | 0 | printf("\033[0;31m%d of %d test case(s) passed\033[0;0m\n", pass, fail + pass); |
90 | 0 | } |
91 | 1 | } else { |
92 | 1 | if (skip > 0) |
93 | 1 | { |
94 | 1 | if (fail == 0) |
95 | 1 | printf("all test case(s) passed, %d test case(s) skipped, congratulations!\n", skip); |
96 | 0 | else |
97 | 0 | printf("%d of %d test case(s) passed, %d test case(s) skipped\n", pass, fail + pass, skip); |
98 | 1 | } else { |
99 | 0 | if (fail == 0) |
100 | 0 | printf("all test case(s) passed, congratulations!\n"); |
101 | 0 | else |
102 | 0 | printf("%d of %d test case(s) passed\n", pass, fail + pass); |
103 | 0 | } |
104 | 1 | } |
105 | 1 | } |
106 | | |
107 | | #if defined(__ELF__) || defined(__APPLE__) |
108 | | // in ELF object format, we can simply query custom section rather than scan through the whole binary memory |
109 | | // to find function pointer. We do this whenever possible because in this way, we don't have access error |
110 | | // when hooking up with memory checkers such as address sanitizer or valgrind |
111 | | |
112 | | #ifdef __ELF__ |
113 | | static case_t __test_case_ctx_probe __attribute__((used, section("case_data_probe"), aligned(8))) = {0}; |
114 | | |
115 | | extern case_t __start_case_data[]; |
116 | | extern case_t __stop_case_data[]; |
117 | | |
118 | | extern case_t __start_case_data_probe[]; |
119 | | extern case_t __stop_case_data_probe[]; |
120 | | #else |
121 | | #include <mach-o/dyld.h> |
122 | | #include <mach-o/getsect.h> |
123 | | #ifdef __LP64__ |
124 | | typedef struct section_64 case_section; |
125 | | typedef struct mach_header_64 case_header; |
126 | | #else |
127 | | typedef struct section case_section; |
128 | | typedef struct mach_header case_header; |
129 | | #endif |
130 | | static case_t __test_case_ctx_probe __attribute__((used, section("__DATA,case_data_probe"), aligned(8))) = {0}; |
131 | | #endif |
132 | | |
133 | | int main(int argc, char** argv) |
134 | 1 | { |
135 | 1 | #ifdef __ELF__ |
136 | 1 | int case_size = (intptr_t)__stop_case_data_probe - (intptr_t)__start_case_data_probe; |
137 | 1 | int test_size = (intptr_t)__stop_case_data - (intptr_t)__start_case_data; |
138 | 1 | unsigned char* start_case_data = (unsigned char*)__start_case_data; |
139 | 1 | unsigned char* stop_case_data = (unsigned char*)__stop_case_data; |
140 | | #else |
141 | | uint32_t image_count = _dyld_image_count(); |
142 | | int case_size = 0; |
143 | | for (uint32_t image_index = 0; !case_size && image_index < image_count; image_index++) |
144 | | { |
145 | | const case_header* mach_header = (const case_header*)_dyld_get_image_header(image_index); |
146 | | unsigned long size; |
147 | | uint8_t *data = getsectiondata(mach_header, "__DATA", "case_data_probe", &size); |
148 | | if (data) |
149 | | case_size = (int)size; |
150 | | } |
151 | | int test_size = 0; |
152 | | unsigned char* start_case_data = 0; |
153 | | unsigned char* stop_case_data = 0; |
154 | | for (uint32_t image_index = 0; image_index < image_count; image_index++) |
155 | | { |
156 | | const case_header* mach_header = (const case_header*)_dyld_get_image_header(image_index); |
157 | | unsigned long size; |
158 | | uint8_t *data = getsectiondata(mach_header, "__DATA", "case_data", &size); |
159 | | if (!data) |
160 | | continue; |
161 | | start_case_data = data; |
162 | | stop_case_data = data + size; |
163 | | test_size = (int)size; |
164 | | break; |
165 | | } |
166 | | #endif |
167 | 1 | char buf[1024]; |
168 | 1 | char* cur_dir = getcwd(buf, 1024); |
169 | 1 | static uint64_t the_sig = 0x883253372849284B; |
170 | 1 | int scan_mode = (test_size % case_size != 0); |
171 | 1 | const char* match_test = (argc == 2) ? argv[1]0 : 0; |
172 | 1 | int i, total = 0; |
173 | 1 | if (!scan_mode) |
174 | 1 | total = test_size / case_size; |
175 | 1.08k | for (i = 0; i < total; i++1.08k ) |
176 | 1.08k | { |
177 | 1.08k | case_t* test_case = (case_t*)(start_case_data + i * case_size); |
178 | | // If it doesn't match well, fallback to scan mode. |
179 | 1.08k | if (test_case->sig_head != the_sig || test_case->sig_tail != the_sig + 2) |
180 | 0 | { |
181 | 0 | scan_mode = 1; |
182 | 0 | break; |
183 | 0 | } |
184 | 1.08k | } |
185 | 1 | int len, pass = 0, skip = 0, fail = 0; |
186 | | // In scan mode, we will scan the whole section for a matching test case. |
187 | 1 | if (scan_mode) |
188 | 0 | { |
189 | 0 | total = 0; |
190 | 0 | len = (intptr_t)stop_case_data - (intptr_t)start_case_data - sizeof(case_t) + 1; |
191 | 0 | for (i = 0; i < len; i++) |
192 | 0 | { |
193 | 0 | case_t* test_case = (case_t*)(start_case_data + i); |
194 | 0 | if (test_case->sig_head == the_sig && test_case->sig_tail == the_sig + 2 && |
195 | 0 | (!match_test || strstr(test_case->name, match_test))) |
196 | 0 | total++; |
197 | 0 | } |
198 | 0 | } |
199 | 1 | if (__test_case_setup) |
200 | 1 | __test_case_setup(); |
201 | 1 | if (scan_mode) |
202 | 0 | { |
203 | 0 | int j = 0; |
204 | 0 | for (i = 0; i < len; i++) |
205 | 0 | { |
206 | 0 | case_t* test_case = (case_t*)(start_case_data + i); |
207 | 0 | if (test_case->sig_head == the_sig && test_case->sig_tail == the_sig + 2 && |
208 | 0 | (!match_test || strstr(test_case->name, match_test))) |
209 | 0 | { |
210 | 0 | case_run(test_case, match_test, j++, total, &pass, &skip, &fail); |
211 | 0 | chdir(cur_dir); |
212 | 0 | } |
213 | 0 | } |
214 | 1 | } else { |
215 | 1 | int matched_total = match_test ? 00 : total; |
216 | 1 | if (match_test) |
217 | 0 | for (i = 0; i < total; i++) |
218 | 0 | { |
219 | 0 | case_t* test_case = (case_t*)(start_case_data + i * case_size); |
220 | 0 | if (strstr(test_case->name, match_test)) |
221 | 0 | matched_total++; |
222 | 0 | } |
223 | 1 | int j = 0; |
224 | | // Simple case, I don't need to scan the data section. |
225 | 1.08k | for (i = 0; i < total; i++1.08k ) |
226 | 1.08k | { |
227 | 1.08k | case_t* test_case = (case_t*)(start_case_data + i * case_size); |
228 | 1.08k | if (!match_test || strstr(test_case->name, match_test)0 ) |
229 | 1.08k | case_run(test_case, match_test, j++, matched_total, &pass, &skip, &fail); |
230 | 1.08k | chdir(cur_dir); |
231 | 1.08k | } |
232 | 1 | } |
233 | 1 | if (__test_case_teardown) |
234 | 0 | __test_case_teardown(); |
235 | 1 | case_conclude(pass, skip, fail); |
236 | 1 | return fail; |
237 | 1 | } |
238 | | |
239 | | #else |
240 | | |
241 | | #include <stdio.h> |
242 | | #include <unistd.h> |
243 | | #include <stdlib.h> |
244 | | #include <fcntl.h> |
245 | | #include <ctype.h> |
246 | | #include <signal.h> |
247 | | #include <setjmp.h> |
248 | | |
249 | | /* the following functions come from Hans Boehm's conservative gc with slightly |
250 | | * modifications, here is the licence: |
251 | | * Copyright (c) 1988, 1989 Hans-J. Boehm, Alan J. Demers |
252 | | * Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved. |
253 | | * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. |
254 | | * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P. |
255 | | |
256 | | * The file linux_threads.c is also |
257 | | * Copyright (c) 1998 by Fergus Henderson. All rights reserved. |
258 | | |
259 | | * The files Makefile.am, and configure.in are |
260 | | * Copyright (c) 2001 by Red Hat Inc. All rights reserved. |
261 | | |
262 | | * Several files supporting GNU-style builds are copyrighted by the Free |
263 | | * Software Foundation, and carry a different license from that given |
264 | | * below. |
265 | | |
266 | | * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
267 | | * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
268 | | |
269 | | * Permission is hereby granted to use or copy this program |
270 | | * for any purpose, provided the above notices are retained on all copies. |
271 | | * Permission to modify the code and to distribute modified code is granted, |
272 | | * provided the above notices are retained, and a notice that the code was |
273 | | * modified is included with the above copyright notice. |
274 | | |
275 | | * A few of the files needed to use the GNU-style build procedure come with |
276 | | * slightly different licenses, though they are all similar in spirit. A few |
277 | | * are GPL'ed, but with an exception that should cover all uses in the |
278 | | * collector. */ |
279 | | |
280 | | /* Repeatedly perform a read call until the buffer is filled or */ |
281 | | /* we encounter EOF. */ |
282 | | static ssize_t case_repeat_read(int fd, char *buf, size_t count) |
283 | | { |
284 | | ssize_t num_read = 0; |
285 | | ssize_t result; |
286 | | |
287 | | while (num_read < count) |
288 | | { |
289 | | result = read(fd, buf + num_read, count - num_read); |
290 | | if (result < 0) |
291 | | return result; |
292 | | if (result == 0) |
293 | | break; |
294 | | num_read += result; |
295 | | } |
296 | | return num_read; |
297 | | } |
298 | | |
299 | | /* Determine the length of a file by incrementally reading it into a buffer */ |
300 | | /* This would be silly to use on a file supporting lseek, but Linux */ |
301 | | /* /proc files usually do not. */ |
302 | | static size_t case_get_file_len(int f) |
303 | | { |
304 | | size_t total = 0; |
305 | | ssize_t result; |
306 | | char buf[500]; |
307 | | |
308 | | do { |
309 | | result = read(f, buf, 500); |
310 | | if (result == -1) |
311 | | return 0; |
312 | | total += result; |
313 | | } while (result > 0); |
314 | | return total; |
315 | | } |
316 | | |
317 | | static size_t case_get_maps_len(void) |
318 | | { |
319 | | int f = open("/proc/self/maps", O_RDONLY); |
320 | | size_t result = case_get_file_len(f); |
321 | | close(f); |
322 | | return result; |
323 | | } |
324 | | |
325 | | /* |
326 | | * Copy the contents of /proc/self/maps to a buffer in our address space. |
327 | | * Return the address of the buffer, or zero on failure. |
328 | | * This code could be simplified if we could determine its size |
329 | | * ahead of time. |
330 | | */ |
331 | | static char* case_get_maps() |
332 | | { |
333 | | int f; |
334 | | int result; |
335 | | static char init_buf[1]; |
336 | | static char *maps_buf = init_buf; |
337 | | static size_t maps_buf_sz = 1; |
338 | | size_t maps_size, old_maps_size = 0; |
339 | | |
340 | | /* Note that in the presence of threads, the maps file can */ |
341 | | /* essentially shrink asynchronously and unexpectedly as */ |
342 | | /* threads that we already think of as dead release their */ |
343 | | /* stacks. And there is no easy way to read the entire */ |
344 | | /* file atomically. This is arguably a misfeature of the */ |
345 | | /* /proc/.../maps interface. */ |
346 | | |
347 | | /* Since we dont believe the file can grow */ |
348 | | /* asynchronously, it should suffice to first determine */ |
349 | | /* the size (using lseek or read), and then to reread the */ |
350 | | /* file. If the size is inconsistent we have to retry. */ |
351 | | /* This only matters with threads enabled, and if we use */ |
352 | | /* this to locate roots (not the default). */ |
353 | | |
354 | | /* Determine the initial size of /proc/self/maps. */ |
355 | | /* Note that lseek doesn't work, at least as of 2.6.15. */ |
356 | | maps_size = case_get_maps_len(); |
357 | | if (0 == maps_size) |
358 | | return 0; |
359 | | |
360 | | /* Read /proc/self/maps, growing maps_buf as necessary. */ |
361 | | /* Note that we may not allocate conventionally, and */ |
362 | | /* thus can't use stdio. */ |
363 | | do { |
364 | | while (maps_size >= maps_buf_sz) |
365 | | { |
366 | | /* Grow only by powers of 2, since we leak "too small" buffers. */ |
367 | | while (maps_size >= maps_buf_sz) |
368 | | maps_buf_sz *= 2; |
369 | | maps_buf = malloc(maps_buf_sz); |
370 | | /* Recompute initial length, since we allocated. */ |
371 | | /* This can only happen a few times per program */ |
372 | | /* execution. */ |
373 | | maps_size = case_get_maps_len(); |
374 | | if (0 == maps_size) |
375 | | return 0; |
376 | | } |
377 | | f = open("/proc/self/maps", O_RDONLY); |
378 | | if (-1 == f) |
379 | | return 0; |
380 | | old_maps_size = maps_size; |
381 | | maps_size = 0; |
382 | | do { |
383 | | result = case_repeat_read(f, maps_buf, maps_buf_sz - 1); |
384 | | if (result <= 0) |
385 | | return 0; |
386 | | maps_size += result; |
387 | | } while (result == maps_buf_sz - 1); |
388 | | close(f); |
389 | | } while (maps_size >= maps_buf_sz || maps_size < old_maps_size); |
390 | | /* In the single-threaded case, the second clause is false. */ |
391 | | maps_buf[maps_size] = '\0'; |
392 | | |
393 | | /* Apply fn to result. */ |
394 | | return maps_buf; |
395 | | } |
396 | | |
397 | | // |
398 | | // GC_parse_map_entry parses an entry from /proc/self/maps so we can |
399 | | // locate all writable data segments that belong to shared libraries. |
400 | | // The format of one of these entries and the fields we care about |
401 | | // is as follows: |
402 | | // XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n |
403 | | // ^^^^^^^^ ^^^^^^^^ ^^^^ ^^ |
404 | | // start end prot maj_dev |
405 | | // |
406 | | // Note that since about august 2003 kernels, the columns no longer have |
407 | | // fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets |
408 | | // anywhere, which is safer anyway. |
409 | | // |
410 | | |
411 | | /* |
412 | | * Assign various fields of the first line in buf_ptr to *start, *end, |
413 | | * *prot, *maj_dev and *mapping_name. Mapping_name may be NULL. |
414 | | * *prot and *mapping_name are assigned pointers into the original |
415 | | * buffer. |
416 | | */ |
417 | | static char* case_parse_map_entry(char* buf_ptr, void** start, void** end, char** prot, unsigned int* maj_dev, char** mapping_name) |
418 | | { |
419 | | char *start_start, *end_start, *maj_dev_start; |
420 | | char *p; |
421 | | char *endp; |
422 | | |
423 | | if (buf_ptr == NULL || *buf_ptr == '\0') |
424 | | return NULL; |
425 | | |
426 | | p = buf_ptr; |
427 | | while (isspace(*p)) |
428 | | ++p; |
429 | | start_start = p; |
430 | | *start = (void*)strtoul(start_start, &endp, 16); |
431 | | p = endp; |
432 | | |
433 | | ++p; |
434 | | end_start = p; |
435 | | *end = (void*)strtoul(end_start, &endp, 16); |
436 | | p = endp; |
437 | | |
438 | | while (isspace(*p)) |
439 | | ++p; |
440 | | *prot = p; |
441 | | /* Skip past protection field to offset field */ |
442 | | while (!isspace(*p)) |
443 | | ++p; |
444 | | while (isspace(*p)) |
445 | | ++p; |
446 | | /* Skip past offset field, which we ignore */ |
447 | | while (!isspace(*p)) |
448 | | ++p; |
449 | | while (isspace(*p)) |
450 | | ++p; |
451 | | maj_dev_start = p; |
452 | | *maj_dev = strtoul(maj_dev_start, NULL, 16); |
453 | | |
454 | | if (mapping_name == 0) |
455 | | { |
456 | | while (*p && *p++ != '\n'); |
457 | | } else { |
458 | | while (*p && *p != '\n' && *p != '/' && *p != '[') |
459 | | p++; |
460 | | *mapping_name = p; |
461 | | while (*p && *p++ != '\n'); |
462 | | } |
463 | | |
464 | | return p; |
465 | | } |
466 | | |
467 | | #define MIN_PAGE_SIZE (256) |
468 | | |
469 | | static jmp_buf case_jmp_buf; |
470 | | |
471 | | static void case_fault_handler(int sig) |
472 | | { |
473 | | longjmp(case_jmp_buf, 1); |
474 | | } |
475 | | |
476 | | static struct sigaction old_segv_act; |
477 | | static struct sigaction old_bus_act; |
478 | | |
479 | | static void case_setup_temporary_fault_handler(void) |
480 | | { |
481 | | struct sigaction act; |
482 | | act.sa_handler = case_fault_handler; |
483 | | act.sa_flags = SA_RESTART; |
484 | | (void)sigemptyset(&act.sa_mask); |
485 | | (void)sigaction(SIGSEGV, &act, &old_segv_act); |
486 | | (void)sigaction(SIGBUS, &act, &old_bus_act); |
487 | | } |
488 | | |
489 | | static void case_reset_fault_handler(void) |
490 | | { |
491 | | (void)sigaction(SIGSEGV, &old_segv_act, 0); |
492 | | (void)sigaction(SIGBUS, &old_bus_act, 0); |
493 | | } |
494 | | |
495 | | static void case_find_limit(char* p, void** start, void** end) |
496 | | { |
497 | | static volatile char* result; |
498 | | static volatile char sink; |
499 | | case_setup_temporary_fault_handler(); |
500 | | if (setjmp(case_jmp_buf) == 0) |
501 | | { |
502 | | result = (char*)((uint64_t)p & (uint64_t)~(MIN_PAGE_SIZE - 1)); |
503 | | for (;;) |
504 | | { |
505 | | result -= MIN_PAGE_SIZE; |
506 | | sink = *result; |
507 | | } |
508 | | } |
509 | | *start = (void*)(result + MIN_PAGE_SIZE); |
510 | | if (setjmp(case_jmp_buf) == 0) |
511 | | { |
512 | | result = (char*)((uint64_t)p & (uint64_t)~(MIN_PAGE_SIZE - 1)); |
513 | | for (;;) |
514 | | { |
515 | | result += MIN_PAGE_SIZE; |
516 | | sink = *result; |
517 | | } |
518 | | } |
519 | | *end = (void*)result; |
520 | | case_reset_fault_handler(); |
521 | | } |
522 | | |
523 | | static char _test_end[8]; |
524 | | |
525 | | int main(int argc, char** argv) |
526 | | { |
527 | | const char* match_test = (argc == 2) ? argv[1] : 0; |
528 | | char* buf = case_get_maps(); |
529 | | void* start; |
530 | | void* end; |
531 | | char* prot[4]; |
532 | | unsigned int maj_dev; |
533 | | static uint64_t the_sig = 0x883253372849284B; |
534 | | if (buf == 0) |
535 | | { |
536 | | case_find_limit(_test_end, &start, &end); |
537 | | } else { |
538 | | do { |
539 | | buf = case_parse_map_entry(buf, &start, &end, (char**)&prot, &maj_dev, 0); |
540 | | if (buf == NULL) |
541 | | break; |
542 | | } while ((intptr_t)start >= (intptr_t)&_test_end || (intptr_t)&_test_end >= (intptr_t)end); |
543 | | } |
544 | | char* start_pointer = (char*)start; |
545 | | int total = 0; |
546 | | int len = (intptr_t)end - (intptr_t)start - sizeof(case_t) + 1; |
547 | | int i; |
548 | | for (i = 0; i < len; i++) |
549 | | { |
550 | | case_t* test_case = (case_t*)(start_pointer + i); |
551 | | if (test_case->sig_head == the_sig && test_case->sig_tail == the_sig + 2 && |
552 | | (!match_test || strstr(test_case->name, match_test))) |
553 | | total++; |
554 | | } |
555 | | char dir_buf[1024]; |
556 | | char* cur_dir = getcwd(dir_buf, 1024); |
557 | | if (__test_case_setup) |
558 | | __test_case_setup(); |
559 | | int j = 0, pass = 0, skip = 0, fail = 0; |
560 | | for (i = 0; i < len; i++) |
561 | | { |
562 | | case_t* test_case = (case_t*)(start_pointer + i); |
563 | | if (test_case->sig_head == the_sig && test_case->sig_tail == the_sig + 2 && |
564 | | (!match_test || strstr(test_case->name, match_test))) |
565 | | { |
566 | | case_run(test_case, match_test, j++, total, &pass, &skip, &fail); |
567 | | chdir(cur_dir); |
568 | | } |
569 | | } |
570 | | if (__test_case_teardown) |
571 | | __test_case_teardown(); |
572 | | case_conclude(pass, skip, fail); |
573 | | return fail; |
574 | | } |
575 | | |
576 | | #endif |
577 | | #endif |