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, 2013
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 "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 * Our exit handler. Called on completion of the test to report a summary of
84 * results provided we're still in the original process. This also handles
85 * printing out the plan if we used plan_lazy(), although that's suppressed if
86 * we never ran a test (due to an early bail, for example).
87 */
88 static void
finish(void)89 finish(void)
90 {
91 unsigned long highest = testnum - 1;
92
93 if (_planned == 0 && !_lazy)
94 return;
95 fflush(stderr);
96 if (_process != 0 && getpid() == _process) {
97 if (_lazy && highest > 0) {
98 printf("1..%lu\n", highest);
99 _planned = highest;
100 }
101 if (_planned > highest)
102 printf("# Looks like you planned %lu test%s but only ran %lu\n",
103 _planned, (_planned > 1 ? "s" : ""), highest);
104 else if (_planned < highest)
105 printf("# Looks like you planned %lu test%s but ran %lu extra\n",
106 _planned, (_planned > 1 ? "s" : ""), highest - _planned);
107 else if (_failed > 0)
108 printf("# Looks like you failed %lu test%s of %lu\n", _failed,
109 (_failed > 1 ? "s" : ""), _planned);
110 else if (_planned > 1)
111 printf("# All %lu tests successful or skipped\n", _planned);
112 else
113 printf("# %lu test successful or skipped\n", _planned);
114 }
115 }
116
117 /*
118 * Initialize things. Turns on line buffering on stdout and then prints out
119 * the number of tests in the test suite.
120 */
121 void
plan(unsigned long count)122 plan(unsigned long count)
123 {
124 if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)
125 fprintf(stderr, "# cannot set stdout to line buffered: %s\n",
126 strerror(errno));
127 fflush(stderr);
128 printf("1..%lu\n", count);
129 testnum = 1;
130 _planned = count;
131 _process = getpid();
132 atexit(finish);
133 }
134
135 /*
136 * Initialize things for lazy planning, where we'll automatically print out a
137 * plan at the end of the program. Turns on line buffering on stdout as well.
138 */
139 void
plan_lazy(void)140 plan_lazy(void)
141 {
142 if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)
143 fprintf(stderr, "# cannot set stdout to line buffered: %s\n",
144 strerror(errno));
145 testnum = 1;
146 _process = getpid();
147 _lazy = 1;
148 atexit(finish);
149 }
150
151 /*
152 * Skip the entire test suite and exits. Should be called instead of plan(),
153 * not after it, since it prints out a special plan line.
154 */
155 void
skip_all(const char * format,...)156 skip_all(const char *format, ...)
157 {
158 fflush(stderr);
159 printf("1..0 # skip");
160 if (format != NULL) {
161 va_list args;
162
163 putchar(' ');
164 va_start(args, format);
165 vprintf(format, args);
166 va_end(args);
167 }
168 putchar('\n');
169 exit(0);
170 }
171
172 /*
173 * Print the test description.
174 */
175 static void
print_desc(const char * format,va_list args)176 print_desc(const char *format, va_list args)
177 {
178 printf(" - ");
179 vprintf(format, args);
180 }
181
182 /*
183 * Takes a boolean success value and assumes the test passes if that value
184 * is true and fails if that value is false.
185 */
186 void
ok(int success,const char * format,...)187 ok(int success, const char *format, ...)
188 {
189 fflush(stderr);
190 printf("%sok %lu", success ? "" : "not ", testnum++);
191 if (!success)
192 _failed++;
193 if (format != NULL) {
194 va_list args;
195
196 va_start(args, format);
197 print_desc(format, args);
198 va_end(args);
199 }
200 putchar('\n');
201 }
202
203 /*
204 * Same as ok(), but takes the format arguments as a va_list.
205 */
206 void
okv(int success,const char * format,va_list args)207 okv(int success, const char *format, va_list args)
208 {
209 fflush(stderr);
210 printf("%sok %lu", success ? "" : "not ", testnum++);
211 if (!success)
212 _failed++;
213 if (format != NULL)
214 print_desc(format, args);
215 putchar('\n');
216 }
217
218 /*
219 * Skip a test.
220 */
221 void
skip(const char * reason,...)222 skip(const char *reason, ...)
223 {
224 fflush(stderr);
225 printf("ok %lu # skip", testnum++);
226 if (reason != NULL) {
227 va_list args;
228
229 va_start(args, reason);
230 putchar(' ');
231 vprintf(reason, args);
232 va_end(args);
233 }
234 putchar('\n');
235 }
236
237 /*
238 * Report the same status on the next count tests.
239 */
240 void
ok_block(unsigned long count,int status,const char * format,...)241 ok_block(unsigned long count, int status, const char *format, ...)
242 {
243 unsigned long i;
244
245 fflush(stderr);
246 for (i = 0; i < count; i++) {
247 printf("%sok %lu", status ? "" : "not ", testnum++);
248 if (!status)
249 _failed++;
250 if (format != NULL) {
251 va_list args;
252
253 va_start(args, format);
254 print_desc(format, args);
255 va_end(args);
256 }
257 putchar('\n');
258 }
259 }
260
261 /*
262 * Skip the next count tests.
263 */
264 void
skip_block(unsigned long count,const char * reason,...)265 skip_block(unsigned long count, const char *reason, ...)
266 {
267 unsigned long i;
268
269 fflush(stderr);
270 for (i = 0; i < count; i++) {
271 printf("ok %lu # skip", testnum++);
272 if (reason != NULL) {
273 va_list args;
274
275 va_start(args, reason);
276 putchar(' ');
277 vprintf(reason, args);
278 va_end(args);
279 }
280 putchar('\n');
281 }
282 }
283
284 /*
285 * Takes an expected integer and a seen integer and assumes the test passes
286 * if those two numbers match.
287 */
288 void
is_int(long long wanted,long long seen,const char * format,...)289 is_int(long long wanted, long long seen, const char *format, ...)
290 {
291 fflush(stderr);
292 if (wanted == seen)
293 printf("ok %lu", testnum++);
294 else {
295 printf("# wanted: %lld\n# seen: %lld\n", wanted, seen);
296 printf("not ok %lu", testnum++);
297 _failed++;
298 }
299 if (format != NULL) {
300 va_list args;
301
302 va_start(args, format);
303 print_desc(format, args);
304 va_end(args);
305 }
306 putchar('\n');
307 }
308
309 /*
310 * Takes a string and what the string should be, and assumes the test passes
311 * if those strings match (using strcmp).
312 */
313 void
is_string(const char * wanted,const char * seen,const char * format,...)314 is_string(const char *wanted, const char *seen, const char *format, ...)
315 {
316 if (wanted == NULL)
317 wanted = "(null)";
318 if (seen == NULL)
319 seen = "(null)";
320 fflush(stderr);
321 if (strcmp(wanted, seen) == 0)
322 printf("ok %lu", testnum++);
323 else {
324 printf("# wanted: %s\n# seen: %s\n", wanted, seen);
325 printf("not ok %lu", testnum++);
326 _failed++;
327 }
328 if (format != NULL) {
329 va_list args;
330
331 va_start(args, format);
332 print_desc(format, args);
333 va_end(args);
334 }
335 putchar('\n');
336 }
337
338 /*
339 * Takes an expected unsigned long and a seen unsigned long and assumes the
340 * test passes if the two numbers match. Otherwise, reports them in hex.
341 */
342 void
is_hex(unsigned long long wanted,unsigned long long seen,const char * format,...)343 is_hex(unsigned long long wanted, unsigned long long seen,
344 const char *format, ...)
345 {
346 fflush(stderr);
347 if (wanted == seen)
348 printf("ok %lu", testnum++);
349 else {
350 printf("# wanted: %llx\n# seen: %llx\n",
351 (unsigned long long) wanted,
352 (unsigned long long) seen);
353 printf("not ok %lu", testnum++);
354 _failed++;
355 }
356 if (format != NULL) {
357 va_list args;
358
359 va_start(args, format);
360 print_desc(format, args);
361 va_end(args);
362 }
363 putchar('\n');
364 }
365
366 /*
367 * Bail out with an error.
368 */
369 void
bail(const char * format,...)370 bail(const char *format, ...)
371 {
372 va_list args;
373
374 fflush(stderr);
375 fflush(stdout);
376 printf("Bail out! ");
377 va_start(args, format);
378 vprintf(format, args);
379 va_end(args);
380 printf("\n");
381 exit(255);
382 }
383
384 /*
385 * Bail out with an error, appending strerror(errno).
386 */
387 void
sysbail(const char * format,...)388 sysbail(const char *format, ...)
389 {
390 va_list args;
391 int oerrno = errno;
392
393 fflush(stderr);
394 fflush(stdout);
395 printf("Bail out! ");
396 va_start(args, format);
397 vprintf(format, args);
398 va_end(args);
399 printf(": %s\n", strerror(oerrno));
400 exit(255);
401 }
402
403 /*
404 * Report a diagnostic to stderr.
405 */
406 void
diag(const char * format,...)407 diag(const char *format, ...)
408 {
409 va_list args;
410
411 fflush(stderr);
412 fflush(stdout);
413 printf("# ");
414 va_start(args, format);
415 vprintf(format, args);
416 va_end(args);
417 printf("\n");
418 }
419
420 /*
421 * Report a diagnostic to stderr, appending strerror(errno).
422 */
423 void
sysdiag(const char * format,...)424 sysdiag(const char *format, ...)
425 {
426 va_list args;
427 int oerrno = errno;
428
429 fflush(stderr);
430 fflush(stdout);
431 printf("# ");
432 va_start(args, format);
433 vprintf(format, args);
434 va_end(args);
435 printf(": %s\n", strerror(oerrno));
436 }
437
438 /*
439 * Allocate cleared memory, reporting a fatal error with bail on failure.
440 */
441 void *
bcalloc(size_t n,size_t size)442 bcalloc(size_t n, size_t size)
443 {
444 void *p;
445
446 p = calloc(n, size);
447 if (p == NULL)
448 sysbail("failed to calloc %lu", (unsigned long)(n * size));
449 return p;
450 }
451
452 /*
453 * Allocate memory, reporting a fatal error with bail on failure.
454 */
455 void *
bmalloc(size_t size)456 bmalloc(size_t size)
457 {
458 void *p;
459
460 p = malloc(size);
461 if (p == NULL)
462 sysbail("failed to malloc %lu", (unsigned long) size);
463 return p;
464 }
465
466 /*
467 * Reallocate memory, reporting a fatal error with bail on failure.
468 */
469 void *
brealloc(void * p,size_t size)470 brealloc(void *p, size_t size)
471 {
472 p = realloc(p, size);
473 if (p == NULL)
474 sysbail("failed to realloc %lu bytes", (unsigned long) size);
475 return p;
476 }
477
478 /*
479 * Copy a string, reporting a fatal error with bail on failure.
480 */
481 char *
bstrdup(const char * s)482 bstrdup(const char *s)
483 {
484 char *p;
485 size_t len;
486
487 len = strlen(s) + 1;
488 p = malloc(len);
489 if (p == NULL)
490 sysbail("failed to strdup %lu bytes", (unsigned long) len);
491 memcpy(p, s, len);
492 return p;
493 }
494
495 /*
496 * Copy up to n characters of a string, reporting a fatal error with bail on
497 * failure. Don't use the system strndup function, since it may not exist and
498 * the TAP library doesn't assume any portability support.
499 */
500 char *
bstrndup(const char * s,size_t n)501 bstrndup(const char *s, size_t n)
502 {
503 const char *p;
504 char *copy;
505 size_t length;
506
507 /* Don't assume that the source string is nul-terminated. */
508 for (p = s; (size_t) (p - s) < n && *p != '\0'; p++)
509 ;
510 length = p - s;
511 copy = malloc(length + 1);
512 if (p == NULL)
513 sysbail("failed to strndup %lu bytes", (unsigned long) length);
514 memcpy(copy, s, length);
515 copy[length] = '\0';
516 return copy;
517 }
518
519 /*
520 * Locate a test file. Given the partial path to a file, look under BUILD and
521 * then SOURCE for the file and return the full path to the file. Returns
522 * NULL if the file doesn't exist. A non-NULL return should be freed with
523 * test_file_path_free().
524 *
525 * This function uses sprintf because it attempts to be independent of all
526 * other portability layers. The use immediately after a memory allocation
527 * should be safe without using snprintf or strlcpy/strlcat.
528 */
529 char *
test_file_path(const char * file)530 test_file_path(const char *file)
531 {
532 char *base;
533 char *path = NULL;
534 size_t length;
535 const char *envs[] = { "BUILD", "SOURCE", NULL };
536 int i;
537
538 for (i = 0; envs[i] != NULL; i++) {
539 base = getenv(envs[i]);
540 if (base == NULL)
541 continue;
542 length = strlen(base) + 1 + strlen(file) + 1;
543 path = bmalloc(length);
544 snprintf(path, length, "%s/%s", base, file);
545 if (access(path, R_OK) == 0)
546 break;
547 free(path);
548 path = NULL;
549 }
550 return path;
551 }
552
553 /*
554 * Free a path returned from test_file_path(). This function exists primarily
555 * for Windows, where memory must be freed from the same library domain that
556 * it was allocated from.
557 */
558 void
test_file_path_free(char * path)559 test_file_path_free(char *path)
560 {
561 if (path != NULL)
562 free(path);
563 }
564
565 /*
566 * Create a temporary directory, tmp, under BUILD if set and the current
567 * directory if it does not. Returns the path to the temporary directory in
568 * newly allocated memory, and calls bail on any failure. The return value
569 * should be freed with test_tmpdir_free.
570 *
571 * This function uses sprintf because it attempts to be independent of all
572 * other portability layers. The use immediately after a memory allocation
573 * should be safe without using snprintf or strlcpy/strlcat.
574 */
575 char *
test_tmpdir(void)576 test_tmpdir(void)
577 {
578 const char *build;
579 char *path = NULL;
580 size_t length;
581
582 build = getenv("BUILD");
583 if (build == NULL)
584 build = ".";
585 length = strlen(build) + strlen("/tmp") + 1;
586 path = bmalloc(length);
587 snprintf(path, length, "%s/tmp", build);
588 if (access(path, X_OK) < 0)
589 if (mkdir(path, 0777) < 0)
590 sysbail("error creating temporary directory %s", path);
591 return path;
592 }
593
594 /*
595 * Free a path returned from test_tmpdir() and attempt to remove the
596 * directory. If we can't delete the directory, don't worry; something else
597 * that hasn't yet cleaned up may still be using it.
598 */
599 void
test_tmpdir_free(char * path)600 test_tmpdir_free(char *path)
601 {
602 rmdir(path);
603 if (path != NULL)
604 free(path);
605 }
606