Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Some utility routines for writing tests. | |
3 | * | |
4 | * Here are a variety of utility routines for writing tests compatible with | |
5 | * the TAP protocol. All routines of the form ok() or is*() take a test | |
6 | * number and some number of appropriate arguments, check to be sure the | |
7 | * results match the expected output using the arguments, and print out | |
8 | * something appropriate for that test number. Other utility routines help in | |
9 | * constructing more complex tests, skipping tests, reporting errors, setting | |
10 | * up the TAP output format, or finding things in the test environment. | |
11 | * | |
12 | * This file is part of C TAP Harness. The current version plus supporting | |
13 | * documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>. | |
14 | * | |
15 | * Copyright 2009, 2010, 2011, 2012 Russ Allbery <rra@stanford.edu> | |
16 | * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012 | |
17 | * The Board of Trustees of the Leland Stanford Junior University | |
18 | * | |
19 | * Permission is hereby granted, free of charge, to any person obtaining a | |
20 | * copy of this software and associated documentation files (the "Software"), | |
21 | * to deal in the Software without restriction, including without limitation | |
22 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
23 | * and/or sell copies of the Software, and to permit persons to whom the | |
24 | * Software is furnished to do so, subject to the following conditions: | |
25 | * | |
26 | * The above copyright notice and this permission notice shall be included in | |
27 | * all copies or substantial portions of the Software. | |
28 | * | |
29 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
30 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
31 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
32 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
33 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
34 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
35 | * DEALINGS IN THE SOFTWARE. | |
36 | */ | |
37 | ||
38 | #include <errno.h> | |
39 | #include <stdarg.h> | |
40 | #include <stdio.h> | |
41 | #include <stdlib.h> | |
42 | #include <string.h> | |
43 | #ifdef _WIN32 | |
44 | # include <direct.h> | |
45 | #else | |
46 | # include <sys/stat.h> | |
47 | #endif | |
48 | #include <sys/types.h> | |
49 | #include <unistd.h> | |
50 | ||
51 | #include <tests/tap/basic.h> | |
52 | ||
53 | /* Windows provides mkdir and rmdir under different names. */ | |
54 | #ifdef _WIN32 | |
55 | # define mkdir(p, m) _mkdir(p) | |
56 | # define rmdir(p) _rmdir(p) | |
57 | #endif | |
58 | ||
59 | /* | |
60 | * The test count. Always contains the number that will be used for the next | |
61 | * test status. | |
62 | */ | |
63 | unsigned long testnum = 1; | |
64 | ||
65 | /* | |
66 | * Status information stored so that we can give a test summary at the end of | |
67 | * the test case. We store the planned final test and the count of failures. | |
68 | * We can get the highest test count from testnum. | |
69 | * | |
70 | * We also store the PID of the process that called plan() and only summarize | |
71 | * results when that process exits, so as to not misreport results in forked | |
72 | * processes. | |
73 | * | |
74 | * If _lazy is true, we're doing lazy planning and will print out the plan | |
75 | * based on the last test number at the end of testing. | |
76 | */ | |
77 | static unsigned long _planned = 0; | |
78 | static unsigned long _failed = 0; | |
79 | static pid_t _process = 0; | |
80 | static int _lazy = 0; | |
81 | ||
82 | ||
83 | /* | |
84 | * Our exit handler. Called on completion of the test to report a summary of | |
85 | * results provided we're still in the original process. This also handles | |
86 | * printing out the plan if we used plan_lazy(), although that's suppressed if | |
87 | * we never ran a test (due to an early bail, for example). | |
88 | */ | |
89 | static void | |
90 | finish(void) | |
91 | { | |
92 | unsigned long highest = testnum - 1; | |
93 | ||
94 | if (_planned == 0 && !_lazy) | |
95 | return; | |
96 | fflush(stderr); | |
97 | if (_process != 0 && getpid() == _process) { | |
98 | if (_lazy && highest > 0) { | |
99 | printf("1..%lu\n", highest); | |
100 | _planned = highest; | |
101 | } | |
102 | if (_planned > highest) | |
103 | printf("# Looks like you planned %lu test%s but only ran %lu\n", | |
104 | _planned, (_planned > 1 ? "s" : ""), highest); | |
105 | else if (_planned < highest) | |
106 | printf("# Looks like you planned %lu test%s but ran %lu extra\n", | |
107 | _planned, (_planned > 1 ? "s" : ""), highest - _planned); | |
108 | else if (_failed > 0) | |
109 | printf("# Looks like you failed %lu test%s of %lu\n", _failed, | |
110 | (_failed > 1 ? "s" : ""), _planned); | |
111 | else if (_planned > 1) | |
112 | printf("# All %lu tests successful or skipped\n", _planned); | |
113 | else | |
114 | printf("# %lu test successful or skipped\n", _planned); | |
115 | } | |
116 | } | |
117 | ||
118 | ||
119 | /* | |
120 | * Initialize things. Turns on line buffering on stdout and then prints out | |
121 | * the number of tests in the test suite. | |
122 | */ | |
123 | void | |
124 | plan(unsigned long count) | |
125 | { | |
126 | if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0) | |
127 | fprintf(stderr, "# cannot set stdout to line buffered: %s\n", | |
128 | strerror(errno)); | |
129 | fflush(stderr); | |
130 | printf("1..%lu\n", count); | |
131 | testnum = 1; | |
132 | _planned = count; | |
133 | _process = getpid(); | |
134 | atexit(finish); | |
135 | } | |
136 | ||
137 | ||
138 | /* | |
139 | * Initialize things for lazy planning, where we'll automatically print out a | |
140 | * plan at the end of the program. Turns on line buffering on stdout as well. | |
141 | */ | |
142 | void | |
143 | plan_lazy(void) | |
144 | { | |
145 | if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0) | |
146 | fprintf(stderr, "# cannot set stdout to line buffered: %s\n", | |
147 | strerror(errno)); | |
148 | testnum = 1; | |
149 | _process = getpid(); | |
150 | _lazy = 1; | |
151 | atexit(finish); | |
152 | } | |
153 | ||
154 | ||
155 | /* | |
156 | * Skip the entire test suite and exits. Should be called instead of plan(), | |
157 | * not after it, since it prints out a special plan line. | |
158 | */ | |
159 | void | |
160 | skip_all(const char *format, ...) | |
161 | { | |
162 | fflush(stderr); | |
163 | printf("1..0 # skip"); | |
164 | if (format != NULL) { | |
165 | va_list args; | |
166 | ||
167 | putchar(' '); | |
168 | va_start(args, format); | |
169 | vprintf(format, args); | |
170 | va_end(args); | |
171 | } | |
172 | putchar('\n'); | |
173 | exit(0); | |
174 | } | |
175 | ||
176 | ||
177 | /* | |
178 | * Print the test description. | |
179 | */ | |
180 | static void | |
181 | print_desc(const char *format, va_list args) | |
182 | { | |
183 | printf(" - "); | |
184 | vprintf(format, args); | |
185 | } | |
186 | ||
187 | ||
188 | /* | |
189 | * Takes a boolean success value and assumes the test passes if that value | |
190 | * is true and fails if that value is false. | |
191 | */ | |
192 | void | |
193 | ok(int success, const char *format, ...) | |
194 | { | |
195 | fflush(stderr); | |
196 | printf("%sok %lu", success ? "" : "not ", testnum++); | |
197 | if (!success) | |
198 | _failed++; | |
199 | if (format != NULL) { | |
200 | va_list args; | |
201 | ||
202 | va_start(args, format); | |
203 | print_desc(format, args); | |
204 | va_end(args); | |
205 | } | |
206 | putchar('\n'); | |
207 | } | |
208 | ||
209 | ||
210 | /* | |
211 | * Same as ok(), but takes the format arguments as a va_list. | |
212 | */ | |
213 | void | |
214 | okv(int success, const char *format, va_list args) | |
215 | { | |
216 | fflush(stderr); | |
217 | printf("%sok %lu", success ? "" : "not ", testnum++); | |
218 | if (!success) | |
219 | _failed++; | |
220 | if (format != NULL) | |
221 | print_desc(format, args); | |
222 | putchar('\n'); | |
223 | } | |
224 | ||
225 | ||
226 | /* | |
227 | * Skip a test. | |
228 | */ | |
229 | void | |
230 | skip(const char *reason, ...) | |
231 | { | |
232 | fflush(stderr); | |
233 | printf("ok %lu # skip", testnum++); | |
234 | if (reason != NULL) { | |
235 | va_list args; | |
236 | ||
237 | va_start(args, reason); | |
238 | putchar(' '); | |
239 | vprintf(reason, args); | |
240 | va_end(args); | |
241 | } | |
242 | putchar('\n'); | |
243 | } | |
244 | ||
245 | ||
246 | /* | |
247 | * Report the same status on the next count tests. | |
248 | */ | |
249 | void | |
250 | ok_block(unsigned long count, int status, const char *format, ...) | |
251 | { | |
252 | unsigned long i; | |
253 | ||
254 | fflush(stderr); | |
255 | for (i = 0; i < count; i++) { | |
256 | printf("%sok %lu", status ? "" : "not ", testnum++); | |
257 | if (!status) | |
258 | _failed++; | |
259 | if (format != NULL) { | |
260 | va_list args; | |
261 | ||
262 | va_start(args, format); | |
263 | print_desc(format, args); | |
264 | va_end(args); | |
265 | } | |
266 | putchar('\n'); | |
267 | } | |
268 | } | |
269 | ||
270 | ||
271 | /* | |
272 | * Skip the next count tests. | |
273 | */ | |
274 | void | |
275 | skip_block(unsigned long count, const char *reason, ...) | |
276 | { | |
277 | unsigned long i; | |
278 | ||
279 | fflush(stderr); | |
280 | for (i = 0; i < count; i++) { | |
281 | printf("ok %lu # skip", testnum++); | |
282 | if (reason != NULL) { | |
283 | va_list args; | |
284 | ||
285 | va_start(args, reason); | |
286 | putchar(' '); | |
287 | vprintf(reason, args); | |
288 | va_end(args); | |
289 | } | |
290 | putchar('\n'); | |
291 | } | |
292 | } | |
293 | ||
294 | ||
295 | /* | |
296 | * Takes an expected integer and a seen integer and assumes the test passes | |
297 | * if those two numbers match. | |
298 | */ | |
299 | void | |
300 | is_int(long wanted, long seen, const char *format, ...) | |
301 | { | |
302 | fflush(stderr); | |
303 | if (wanted == seen) | |
304 | printf("ok %lu", testnum++); | |
305 | else { | |
306 | printf("# wanted: %ld\n# seen: %ld\n", wanted, seen); | |
307 | printf("not ok %lu", testnum++); | |
308 | _failed++; | |
309 | } | |
310 | if (format != NULL) { | |
311 | va_list args; | |
312 | ||
313 | va_start(args, format); | |
314 | print_desc(format, args); | |
315 | va_end(args); | |
316 | } | |
317 | putchar('\n'); | |
318 | } | |
319 | ||
320 | ||
321 | /* | |
322 | * Takes a string and what the string should be, and assumes the test passes | |
323 | * if those strings match (using strcmp). | |
324 | */ | |
325 | void | |
326 | is_string(const char *wanted, const char *seen, const char *format, ...) | |
327 | { | |
328 | if (wanted == NULL) | |
329 | wanted = "(null)"; | |
330 | if (seen == NULL) | |
331 | seen = "(null)"; | |
332 | fflush(stderr); | |
333 | if (strcmp(wanted, seen) == 0) | |
334 | printf("ok %lu", testnum++); | |
335 | else { | |
336 | printf("# wanted: %s\n# seen: %s\n", wanted, seen); | |
337 | printf("not ok %lu", testnum++); | |
338 | _failed++; | |
339 | } | |
340 | if (format != NULL) { | |
341 | va_list args; | |
342 | ||
343 | va_start(args, format); | |
344 | print_desc(format, args); | |
345 | va_end(args); | |
346 | } | |
347 | putchar('\n'); | |
348 | } | |
349 | ||
350 | ||
351 | /* | |
352 | * Takes an expected unsigned long and a seen unsigned long and assumes the | |
353 | * test passes if the two numbers match. Otherwise, reports them in hex. | |
354 | */ | |
355 | void | |
356 | is_hex(unsigned long wanted, unsigned long seen, const char *format, ...) | |
357 | { | |
358 | fflush(stderr); | |
359 | if (wanted == seen) | |
360 | printf("ok %lu", testnum++); | |
361 | else { | |
362 | printf("# wanted: %lx\n# seen: %lx\n", (unsigned long) wanted, | |
363 | (unsigned long) seen); | |
364 | printf("not ok %lu", testnum++); | |
365 | _failed++; | |
366 | } | |
367 | if (format != NULL) { | |
368 | va_list args; | |
369 | ||
370 | va_start(args, format); | |
371 | print_desc(format, args); | |
372 | va_end(args); | |
373 | } | |
374 | putchar('\n'); | |
375 | } | |
376 | ||
377 | ||
378 | /* | |
379 | * Bail out with an error. | |
380 | */ | |
381 | void | |
382 | bail(const char *format, ...) | |
383 | { | |
384 | va_list args; | |
385 | ||
386 | fflush(stderr); | |
387 | fflush(stdout); | |
388 | printf("Bail out! "); | |
389 | va_start(args, format); | |
390 | vprintf(format, args); | |
391 | va_end(args); | |
392 | printf("\n"); | |
393 | exit(1); | |
394 | } | |
395 | ||
396 | ||
397 | /* | |
398 | * Bail out with an error, appending strerror(errno). | |
399 | */ | |
400 | void | |
401 | sysbail(const char *format, ...) | |
402 | { | |
403 | va_list args; | |
404 | int oerrno = errno; | |
405 | ||
406 | fflush(stderr); | |
407 | fflush(stdout); | |
408 | printf("Bail out! "); | |
409 | va_start(args, format); | |
410 | vprintf(format, args); | |
411 | va_end(args); | |
412 | printf(": %s\n", strerror(oerrno)); | |
413 | exit(1); | |
414 | } | |
415 | ||
416 | ||
417 | /* | |
418 | * Report a diagnostic to stderr. | |
419 | */ | |
420 | void | |
421 | diag(const char *format, ...) | |
422 | { | |
423 | va_list args; | |
424 | ||
425 | fflush(stderr); | |
426 | fflush(stdout); | |
427 | printf("# "); | |
428 | va_start(args, format); | |
429 | vprintf(format, args); | |
430 | va_end(args); | |
431 | printf("\n"); | |
432 | } | |
433 | ||
434 | ||
435 | /* | |
436 | * Report a diagnostic to stderr, appending strerror(errno). | |
437 | */ | |
438 | void | |
439 | sysdiag(const char *format, ...) | |
440 | { | |
441 | va_list args; | |
442 | int oerrno = errno; | |
443 | ||
444 | fflush(stderr); | |
445 | fflush(stdout); | |
446 | printf("# "); | |
447 | va_start(args, format); | |
448 | vprintf(format, args); | |
449 | va_end(args); | |
450 | printf(": %s\n", strerror(oerrno)); | |
451 | } | |
452 | ||
453 | ||
454 | /* | |
455 | * Allocate cleared memory, reporting a fatal error with bail on failure. | |
456 | */ | |
457 | void * | |
458 | bcalloc(size_t n, size_t size) | |
459 | { | |
460 | void *p; | |
461 | ||
462 | p = calloc(n, size); | |
463 | if (p == NULL) | |
464 | sysbail("failed to calloc %lu", (unsigned long)(n * size)); | |
465 | return p; | |
466 | } | |
467 | ||
468 | ||
469 | /* | |
470 | * Allocate memory, reporting a fatal error with bail on failure. | |
471 | */ | |
472 | void * | |
473 | bmalloc(size_t size) | |
474 | { | |
475 | void *p; | |
476 | ||
477 | p = malloc(size); | |
478 | if (p == NULL) | |
479 | sysbail("failed to malloc %lu", (unsigned long) size); | |
480 | return p; | |
481 | } | |
482 | ||
483 | ||
484 | /* | |
485 | * Reallocate memory, reporting a fatal error with bail on failure. | |
486 | */ | |
487 | void * | |
488 | brealloc(void *p, size_t size) | |
489 | { | |
490 | p = realloc(p, size); | |
491 | if (p == NULL) | |
492 | sysbail("failed to realloc %lu bytes", (unsigned long) size); | |
493 | return p; | |
494 | } | |
495 | ||
496 | ||
497 | /* | |
498 | * Copy a string, reporting a fatal error with bail on failure. | |
499 | */ | |
500 | char * | |
501 | bstrdup(const char *s) | |
502 | { | |
503 | char *p; | |
504 | size_t len; | |
505 | ||
506 | len = strlen(s) + 1; | |
507 | p = malloc(len); | |
508 | if (p == NULL) | |
509 | sysbail("failed to strdup %lu bytes", (unsigned long) len); | |
510 | memcpy(p, s, len); | |
511 | return p; | |
512 | } | |
513 | ||
514 | ||
515 | /* | |
516 | * Copy up to n characters of a string, reporting a fatal error with bail on | |
517 | * failure. Don't use the system strndup function, since it may not exist and | |
518 | * the TAP library doesn't assume any portability support. | |
519 | */ | |
520 | char * | |
521 | bstrndup(const char *s, size_t n) | |
522 | { | |
523 | const char *p; | |
524 | char *copy; | |
525 | size_t length; | |
526 | ||
527 | /* Don't assume that the source string is nul-terminated. */ | |
528 | for (p = s; (size_t) (p - s) < n && *p != '\0'; p++) | |
529 | ; | |
530 | length = p - s; | |
531 | copy = malloc(length + 1); | |
532 | if (p == NULL) | |
533 | sysbail("failed to strndup %lu bytes", (unsigned long) length); | |
534 | memcpy(copy, s, length); | |
535 | copy[length] = '\0'; | |
536 | return copy; | |
537 | } | |
538 | ||
539 | ||
540 | /* | |
541 | * Locate a test file. Given the partial path to a file, look under BUILD and | |
542 | * then SOURCE for the file and return the full path to the file. Returns | |
543 | * NULL if the file doesn't exist. A non-NULL return should be freed with | |
544 | * test_file_path_free(). | |
545 | * | |
546 | * This function uses sprintf because it attempts to be independent of all | |
547 | * other portability layers. The use immediately after a memory allocation | |
548 | * should be safe without using snprintf or strlcpy/strlcat. | |
549 | */ | |
550 | char * | |
551 | test_file_path(const char *file) | |
552 | { | |
553 | char *base; | |
554 | char *path = NULL; | |
555 | size_t length; | |
556 | const char *envs[] = { "BUILD", "SOURCE", NULL }; | |
557 | int i; | |
558 | ||
559 | for (i = 0; envs[i] != NULL; i++) { | |
560 | base = getenv(envs[i]); | |
561 | if (base == NULL) | |
562 | continue; | |
563 | length = strlen(base) + 1 + strlen(file) + 1; | |
564 | path = bmalloc(length); | |
565 | sprintf(path, "%s/%s", base, file); | |
566 | if (access(path, R_OK) == 0) | |
567 | break; | |
568 | free(path); | |
569 | path = NULL; | |
570 | } | |
571 | return path; | |
572 | } | |
573 | ||
574 | ||
575 | /* | |
576 | * Free a path returned from test_file_path(). This function exists primarily | |
577 | * for Windows, where memory must be freed from the same library domain that | |
578 | * it was allocated from. | |
579 | */ | |
580 | void | |
581 | test_file_path_free(char *path) | |
582 | { | |
583 | if (path != NULL) | |
584 | free(path); | |
585 | } | |
586 | ||
587 | ||
588 | /* | |
589 | * Create a temporary directory, tmp, under BUILD if set and the current | |
590 | * directory if it does not. Returns the path to the temporary directory in | |
591 | * newly allocated memory, and calls bail on any failure. The return value | |
592 | * should be freed with test_tmpdir_free. | |
593 | * | |
594 | * This function uses sprintf because it attempts to be independent of all | |
595 | * other portability layers. The use immediately after a memory allocation | |
596 | * should be safe without using snprintf or strlcpy/strlcat. | |
597 | */ | |
598 | char * | |
599 | test_tmpdir(void) | |
600 | { | |
601 | const char *build; | |
602 | char *path = NULL; | |
603 | size_t length; | |
604 | ||
605 | build = getenv("BUILD"); | |
606 | if (build == NULL) | |
607 | build = "."; | |
608 | length = strlen(build) + strlen("/tmp") + 1; | |
609 | path = bmalloc(length); | |
610 | sprintf(path, "%s/tmp", build); | |
611 | if (access(path, X_OK) < 0) | |
612 | if (mkdir(path, 0777) < 0) | |
613 | sysbail("error creating temporary directory %s", path); | |
614 | return path; | |
615 | } | |
616 | ||
617 | ||
618 | /* | |
619 | * Free a path returned from test_tmpdir() and attempt to remove the | |
620 | * directory. If we can't delete the directory, don't worry; something else | |
621 | * that hasn't yet cleaned up may still be using it. | |
622 | */ | |
623 | void | |
624 | test_tmpdir_free(char *path) | |
625 | { | |
626 | rmdir(path); | |
627 | if (path != NULL) | |
628 | free(path); | |
629 | } |