SYSENTER/SYSCALL support
[minix.git] / commands / tar / test / main.c
blob6028d7789a4a7e33652daa8afca5856ad67289ba
1 /*
2 * Copyright (c) 2003-2009 Tim Kientzle
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "test.h"
27 #include <errno.h>
28 #include <locale.h>
29 #include <stdarg.h>
30 #include <time.h>
33 * This same file is used pretty much verbatim for all test harnesses.
35 * The next few lines are the only differences.
36 * TODO: Move this into a separate configuration header, have all test
37 * suites share one copy of this file.
39 __FBSDID("$FreeBSD: src/usr.bin/tar/test/main.c,v 1.6 2008/11/05 06:40:53 kientzle Exp $");
40 #define KNOWNREF "test_patterns_2.tar.uu"
41 #define ENVBASE "BSDTAR" /* Prefix for environment variables. */
42 #define PROGRAM "bsdtar" /* Name of program being tested. */
43 #undef LIBRARY /* Not testing a library. */
44 #undef EXTRA_DUMP /* How to dump extra data */
45 /* How to generate extra version info. */
46 #define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "")
50 * Windows support routines
52 * Note: Configuration is a tricky issue. Using HAVE_* feature macros
53 * in the test harness is dangerous because they cover up
54 * configuration errors. The classic example of this is omitting a
55 * configure check. If libarchive and libarchive_test both look for
56 * the same feature macro, such errors are hard to detect. Platform
57 * macros (e.g., _WIN32 or __GNUC__) are a little better, but can
58 * easily lead to very messy code. It's best to limit yourself
59 * to only the most generic programming techniques in the test harness
60 * and thus avoid conditionals altogether. Where that's not possible,
61 * try to minimize conditionals by grouping platform-specific tests in
62 * one place (e.g., test_acl_freebsd) or by adding new assert()
63 * functions (e.g., assertMakeHardlink()) to cover up platform
64 * differences. Platform-specific coding in libarchive_test is often
65 * a symptom that some capability is missing from libarchive itself.
67 #if defined(_WIN32) && !defined(__CYGWIN__)
68 #include <io.h>
69 #include <windows.h>
70 #ifndef F_OK
71 #define F_OK (0)
72 #endif
73 #ifndef S_ISDIR
74 #define S_ISDIR(m) ((m) & _S_IFDIR)
75 #endif
76 #ifndef S_ISREG
77 #define S_ISREG(m) ((m) & _S_IFREG)
78 #endif
79 #if !defined(__BORLANDC__)
80 #define access _access
81 #undef chdir
82 #define chdir _chdir
83 #endif
84 #ifndef fileno
85 #define fileno _fileno
86 #endif
87 /*#define fstat _fstat64*/
88 #if !defined(__BORLANDC__)
89 #define getcwd _getcwd
90 #endif
91 #define lstat stat
92 /*#define lstat _stat64*/
93 /*#define stat _stat64*/
94 #define rmdir _rmdir
95 #if !defined(__BORLANDC__)
96 #define strdup _strdup
97 #define umask _umask
98 #endif
99 #define int64_t __int64
100 #endif
102 #if defined(HAVE__CrtSetReportMode)
103 # include <crtdbg.h>
104 #endif
106 #if defined(_WIN32) && !defined(__CYGWIN__)
107 void *GetFunctionKernel32(const char *name)
109 static HINSTANCE lib;
110 static int set;
111 if (!set) {
112 set = 1;
113 lib = LoadLibrary("kernel32.dll");
115 if (lib == NULL) {
116 fprintf(stderr, "Can't load kernel32.dll?!\n");
117 exit(1);
119 return (void *)GetProcAddress(lib, name);
122 static int
123 my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags)
125 static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD);
126 static int set;
127 if (!set) {
128 set = 1;
129 f = GetFunctionKernel32("CreateSymbolicLinkA");
131 return f == NULL ? 0 : (*f)(linkname, target, flags);
134 static int
135 my_CreateHardLinkA(const char *linkname, const char *target)
137 static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES);
138 static int set;
139 if (!set) {
140 set = 1;
141 f = GetFunctionKernel32("CreateHardLinkA");
143 return f == NULL ? 0 : (*f)(linkname, target, NULL);
147 my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi)
149 HANDLE h;
150 int r;
152 memset(bhfi, 0, sizeof(*bhfi));
153 h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL,
154 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
155 if (h == INVALID_HANDLE_VALUE)
156 return (0);
157 r = GetFileInformationByHandle(h, bhfi);
158 CloseHandle(h);
159 return (r);
161 #endif
163 #if defined(HAVE__CrtSetReportMode)
164 static void
165 invalid_parameter_handler(const wchar_t * expression,
166 const wchar_t * function, const wchar_t * file,
167 unsigned int line, uintptr_t pReserved)
169 /* nop */
171 #endif
175 * OPTIONS FLAGS
179 /* Enable core dump on failure. */
180 static int dump_on_failure = 0;
181 /* Default is to remove temp dirs and log data for successful tests. */
182 static int keep_temp_files = 0;
183 /* Default is to just report pass/fail for each test. */
184 static int verbosity = 0;
185 #define VERBOSITY_SUMMARY_ONLY -1 /* -q */
186 #define VERBOSITY_PASSFAIL 0 /* Default */
187 #define VERBOSITY_LIGHT_REPORT 1 /* -v */
188 #define VERBOSITY_FULL 2 /* -vv */
189 /* A few places generate even more output for verbosity > VERBOSITY_FULL,
190 * mostly for debugging the test harness itself. */
191 /* Cumulative count of assertion failures. */
192 static int failures = 0;
193 /* Cumulative count of reported skips. */
194 static int skips = 0;
195 /* Cumulative count of assertions checked. */
196 static int assertions = 0;
198 /* Directory where uuencoded reference files can be found. */
199 static const char *refdir;
202 * Report log information selectively to console and/or disk log.
204 static int log_console = 0;
205 static FILE *logfile;
206 static void
207 vlogprintf(const char *fmt, va_list ap)
209 #ifdef va_copy
210 va_list lfap;
211 va_copy(lfap, ap);
212 #endif
213 if (log_console)
214 vfprintf(stdout, fmt, ap);
215 if (logfile != NULL)
216 #ifdef va_copy
217 vfprintf(logfile, fmt, lfap);
218 va_end(lfap);
219 #else
220 vfprintf(logfile, fmt, ap);
221 #endif
224 static void
225 logprintf(const char *fmt, ...)
227 va_list ap;
228 va_start(ap, fmt);
229 vlogprintf(fmt, ap);
230 va_end(ap);
233 /* Set up a message to display only if next assertion fails. */
234 static char msgbuff[4096];
235 static const char *msg, *nextmsg;
236 void
237 failure(const char *fmt, ...)
239 va_list ap;
240 va_start(ap, fmt);
241 vsprintf(msgbuff, fmt, ap);
242 va_end(ap);
243 nextmsg = msgbuff;
247 * Copy arguments into file-local variables.
248 * This was added to permit vararg assert() functions without needing
249 * variadic wrapper macros. Turns out that the vararg capability is almost
250 * never used, so almost all of the vararg assertions can be simplified
251 * by removing the vararg capability and reworking the wrapper macro to
252 * pass __FILE__, __LINE__ directly into the function instead of using
253 * this hook. I suspect this machinery is used so rarely that we
254 * would be better off just removing it entirely. That would simplify
255 * the code here noticably.
257 static const char *test_filename;
258 static int test_line;
259 static void *test_extra;
260 void assertion_setup(const char *filename, int line)
262 test_filename = filename;
263 test_line = line;
266 /* Called at the beginning of each assert() function. */
267 static void
268 assertion_count(const char *file, int line)
270 (void)file; /* UNUSED */
271 (void)line; /* UNUSED */
272 ++assertions;
273 /* Proper handling of "failure()" message. */
274 msg = nextmsg;
275 nextmsg = NULL;
276 /* Uncomment to print file:line after every assertion.
277 * Verbose, but occasionally useful in tracking down crashes. */
278 /* printf("Checked %s:%d\n", file, line); */
282 * For each test source file, we remember how many times each
283 * assertion was reported. Cleared before each new test,
284 * used by test_summarize().
286 static struct line {
287 int count;
288 int skip;
289 } failed_lines[10000];
291 /* Count this failure, setup up log destination and handle initial report. */
292 static void
293 failure_start(const char *filename, int line, const char *fmt, ...)
295 va_list ap;
297 /* Record another failure for this line. */
298 ++failures;
299 /* test_filename = filename; */
300 failed_lines[line].count++;
302 /* Determine whether to log header to console. */
303 switch (verbosity) {
304 case VERBOSITY_FULL:
305 log_console = 1;
306 break;
307 case VERBOSITY_LIGHT_REPORT:
308 log_console = (failed_lines[line].count < 2);
309 break;
310 default:
311 log_console = 0;
314 /* Log file:line header for this failure */
315 va_start(ap, fmt);
316 #if _MSC_VER
317 logprintf("%s(%d): ", filename, line);
318 #else
319 logprintf("%s:%d: ", filename, line);
320 #endif
321 vlogprintf(fmt, ap);
322 va_end(ap);
323 logprintf("\n");
325 if (msg != NULL && msg[0] != '\0') {
326 logprintf(" Description: %s\n", msg);
327 msg = NULL;
330 /* Determine whether to log details to console. */
331 if (verbosity == VERBOSITY_LIGHT_REPORT)
332 log_console = 0;
335 /* Complete reporting of failed tests. */
337 * The 'extra' hook here is used by libarchive to include libarchive
338 * error messages with assertion failures. It could also be used
339 * to add strerror() output, for example. Just define the EXTRA_DUMP()
340 * macro appropriately.
342 static void
343 failure_finish(void *extra)
345 (void)extra; /* UNUSED (maybe) */
346 #ifdef EXTRA_DUMP
347 if (extra != NULL)
348 logprintf(" detail: %s\n", EXTRA_DUMP(extra));
349 #endif
351 if (dump_on_failure) {
352 fprintf(stderr,
353 " *** forcing core dump so failure can be debugged ***\n");
354 *(char *)(NULL) = 0;
355 exit(1);
359 /* Inform user that we're skipping some checks. */
360 void
361 test_skipping(const char *fmt, ...)
363 char buff[1024];
364 va_list ap;
366 va_start(ap, fmt);
367 vsprintf(buff, fmt, ap);
368 va_end(ap);
369 /* failure_start() isn't quite right, but is awfully convenient. */
370 failure_start(test_filename, test_line, "SKIPPING: %s", buff);
371 --failures; /* Undo failures++ in failure_start() */
372 /* Don't failure_finish() here. */
373 /* Mark as skip, so doesn't count as failed test. */
374 failed_lines[test_line].skip = 1;
375 ++skips;
380 * ASSERTIONS
384 /* Generic assert() just displays the failed condition. */
386 assertion_assert(const char *file, int line, int value,
387 const char *condition, void *extra)
389 assertion_count(file, line);
390 if (!value) {
391 failure_start(file, line, "Assertion failed: %s", condition);
392 failure_finish(extra);
394 return (value);
397 /* chdir() and report any errors */
399 assertion_chdir(const char *file, int line, const char *pathname)
401 assertion_count(file, line);
402 if (chdir(pathname) == 0)
403 return (1);
404 failure_start(file, line, "chdir(\"%s\")", pathname);
405 failure_finish(NULL);
406 return (0);
410 /* Verify two integers are equal. */
412 assertion_equal_int(const char *file, int line,
413 long long v1, const char *e1, long long v2, const char *e2, void *extra)
415 assertion_count(file, line);
416 if (v1 == v2)
417 return (1);
418 failure_start(file, line, "%s != %s", e1, e2);
419 logprintf(" %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1);
420 logprintf(" %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2);
421 failure_finish(extra);
422 return (0);
425 static void strdump(const char *e, const char *p)
427 const char *q = p;
429 logprintf(" %s = ", e);
430 if (p == NULL) {
431 logprintf("NULL");
432 return;
434 logprintf("\"");
435 while (*p != '\0') {
436 unsigned int c = 0xff & *p++;
437 switch (c) {
438 case '\a': printf("\a"); break;
439 case '\b': printf("\b"); break;
440 case '\n': printf("\n"); break;
441 case '\r': printf("\r"); break;
442 default:
443 if (c >= 32 && c < 127)
444 logprintf("%c", c);
445 else
446 logprintf("\\x%02X", c);
449 logprintf("\"");
450 logprintf(" (length %d)\n", q == NULL ? -1 : (int)strlen(q));
453 /* Verify two strings are equal, dump them if not. */
455 assertion_equal_string(const char *file, int line,
456 const char *v1, const char *e1,
457 const char *v2, const char *e2,
458 void *extra)
460 assertion_count(file, line);
461 if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0))
462 return (1);
463 failure_start(file, line, "%s != %s", e1, e2);
464 strdump(e1, v1);
465 strdump(e2, v2);
466 failure_finish(extra);
467 return (0);
470 static void
471 wcsdump(const char *e, const wchar_t *w)
473 logprintf(" %s = ", e);
474 if (w == NULL) {
475 logprintf("(null)");
476 return;
478 logprintf("\"");
479 while (*w != L'\0') {
480 unsigned int c = *w++;
481 if (c >= 32 && c < 127)
482 logprintf("%c", c);
483 else if (c < 256)
484 logprintf("\\x%02X", c);
485 else if (c < 0x10000)
486 logprintf("\\u%04X", c);
487 else
488 logprintf("\\U%08X", c);
490 logprintf("\"\n");
493 /* Verify that two wide strings are equal, dump them if not. */
495 assertion_equal_wstring(const char *file, int line,
496 const wchar_t *v1, const char *e1,
497 const wchar_t *v2, const char *e2,
498 void *extra)
500 assertion_count(file, line);
501 if (v1 == v2 || wcscmp(v1, v2) == 0)
502 return (1);
503 failure_start(file, line, "%s != %s", e1, e2);
504 wcsdump(e1, v1);
505 wcsdump(e2, v2);
506 failure_finish(extra);
507 return (0);
511 * Pretty standard hexdump routine. As a bonus, if ref != NULL, then
512 * any bytes in p that differ from ref will be highlighted with '_'
513 * before and after the hex value.
515 static void
516 hexdump(const char *p, const char *ref, size_t l, size_t offset)
518 size_t i, j;
519 char sep;
521 if (p == NULL) {
522 logprintf("(null)\n");
523 return;
525 for(i=0; i < l; i+=16) {
526 logprintf("%04x", (unsigned)(i + offset));
527 sep = ' ';
528 for (j = 0; j < 16 && i + j < l; j++) {
529 if (ref != NULL && p[i + j] != ref[i + j])
530 sep = '_';
531 logprintf("%c%02x", sep, 0xff & (int)p[i+j]);
532 if (ref != NULL && p[i + j] == ref[i + j])
533 sep = ' ';
535 for (; j < 16; j++) {
536 logprintf("%c ", sep);
537 sep = ' ';
539 logprintf("%c", sep);
540 for (j=0; j < 16 && i + j < l; j++) {
541 int c = p[i + j];
542 if (c >= ' ' && c <= 126)
543 logprintf("%c", c);
544 else
545 logprintf(".");
547 logprintf("\n");
551 /* Verify that two blocks of memory are the same, display the first
552 * block of differences if they're not. */
554 assertion_equal_mem(const char *file, int line,
555 const void *_v1, const char *e1,
556 const void *_v2, const char *e2,
557 size_t l, const char *ld, void *extra)
559 const char *v1 = (const char *)_v1;
560 const char *v2 = (const char *)_v2;
561 size_t offset;
563 assertion_count(file, line);
564 if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0))
565 return (1);
567 failure_start(file, line, "%s != %s", e1, e2);
568 logprintf(" size %s = %d\n", ld, (int)l);
569 /* Dump 48 bytes (3 lines) so that the first difference is
570 * in the second line. */
571 offset = 0;
572 while (l > 64 && memcmp(v1, v2, 32) == 0) {
573 /* Two lines agree, so step forward one line. */
574 v1 += 16;
575 v2 += 16;
576 l -= 16;
577 offset += 16;
579 logprintf(" Dump of %s\n", e1);
580 hexdump(v1, v2, l < 64 ? l : 64, offset);
581 logprintf(" Dump of %s\n", e2);
582 hexdump(v2, v1, l < 64 ? l : 64, offset);
583 logprintf("\n");
584 failure_finish(extra);
585 return (0);
588 /* Verify that the named file exists and is empty. */
590 assertion_empty_file(const char *f1fmt, ...)
592 char buff[1024];
593 char f1[1024];
594 struct stat st;
595 va_list ap;
596 ssize_t s;
597 FILE *f;
599 assertion_count(test_filename, test_line);
600 va_start(ap, f1fmt);
601 vsprintf(f1, f1fmt, ap);
602 va_end(ap);
604 if (stat(f1, &st) != 0) {
605 failure_start(test_filename, test_line, "Stat failed: %s", f1);
606 failure_finish(NULL);
607 return (0);
609 if (st.st_size == 0)
610 return (1);
612 failure_start(test_filename, test_line, "File should be empty: %s", f1);
613 logprintf(" File size: %d\n", (int)st.st_size);
614 logprintf(" Contents:\n");
615 f = fopen(f1, "rb");
616 if (f == NULL) {
617 logprintf(" Unable to open %s\n", f1);
618 } else {
619 s = ((off_t)sizeof(buff) < st.st_size) ?
620 (ssize_t)sizeof(buff) : (ssize_t)st.st_size;
621 s = fread(buff, 1, s, f);
622 hexdump(buff, NULL, s, 0);
623 fclose(f);
625 failure_finish(NULL);
626 return (0);
629 /* Verify that the named file exists and is not empty. */
631 assertion_non_empty_file(const char *f1fmt, ...)
633 char f1[1024];
634 struct stat st;
635 va_list ap;
637 assertion_count(test_filename, test_line);
638 va_start(ap, f1fmt);
639 vsprintf(f1, f1fmt, ap);
640 va_end(ap);
642 if (stat(f1, &st) != 0) {
643 failure_start(test_filename, test_line, "Stat failed: %s", f1);
644 failure_finish(NULL);
645 return (0);
647 if (st.st_size == 0) {
648 failure_start(test_filename, test_line, "File empty: %s", f1);
649 failure_finish(NULL);
650 return (0);
652 return (1);
655 /* Verify that two files have the same contents. */
656 /* TODO: hexdump the first bytes that actually differ. */
658 assertion_equal_file(const char *fn1, const char *f2pattern, ...)
660 char fn2[1024];
661 va_list ap;
662 char buff1[1024];
663 char buff2[1024];
664 FILE *f1, *f2;
665 int n1, n2;
667 assertion_count(test_filename, test_line);
668 va_start(ap, f2pattern);
669 vsprintf(fn2, f2pattern, ap);
670 va_end(ap);
672 f1 = fopen(fn1, "rb");
673 f2 = fopen(fn2, "rb");
674 for (;;) {
675 n1 = fread(buff1, 1, sizeof(buff1), f1);
676 n2 = fread(buff2, 1, sizeof(buff2), f2);
677 if (n1 != n2)
678 break;
679 if (n1 == 0 && n2 == 0) {
680 fclose(f1);
681 fclose(f2);
682 return (1);
684 if (memcmp(buff1, buff2, n1) != 0)
685 break;
687 fclose(f1);
688 fclose(f2);
689 failure_start(test_filename, test_line, "Files not identical");
690 logprintf(" file1=\"%s\"\n", fn1);
691 logprintf(" file2=\"%s\"\n", fn2);
692 failure_finish(test_extra);
693 return (0);
696 /* Verify that the named file does exist. */
698 assertion_file_exists(const char *fpattern, ...)
700 char f[1024];
701 va_list ap;
703 assertion_count(test_filename, test_line);
704 va_start(ap, fpattern);
705 vsprintf(f, fpattern, ap);
706 va_end(ap);
708 #if defined(_WIN32) && !defined(__CYGWIN__)
709 if (!_access(f, 0))
710 return (1);
711 #else
712 if (!access(f, F_OK))
713 return (1);
714 #endif
715 failure_start(test_filename, test_line, "File should exist: %s", f);
716 failure_finish(test_extra);
717 return (0);
720 /* Verify that the named file doesn't exist. */
722 assertion_file_not_exists(const char *fpattern, ...)
724 char f[1024];
725 va_list ap;
727 assertion_count(test_filename, test_line);
728 va_start(ap, fpattern);
729 vsprintf(f, fpattern, ap);
730 va_end(ap);
732 #if defined(_WIN32) && !defined(__CYGWIN__)
733 if (_access(f, 0))
734 return (1);
735 #else
736 if (access(f, F_OK))
737 return (1);
738 #endif
739 failure_start(test_filename, test_line, "File should not exist: %s", f);
740 failure_finish(test_extra);
741 return (0);
744 /* Compare the contents of a file to a block of memory. */
746 assertion_file_contents(const void *buff, int s, const char *fpattern, ...)
748 char fn[1024];
749 va_list ap;
750 char *contents;
751 FILE *f;
752 int n;
754 assertion_count(test_filename, test_line);
755 va_start(ap, fpattern);
756 vsprintf(fn, fpattern, ap);
757 va_end(ap);
759 f = fopen(fn, "rb");
760 if (f == NULL) {
761 failure_start(test_filename, test_line,
762 "File should exist: %s", fn);
763 failure_finish(test_extra);
764 return (0);
766 contents = malloc(s * 2);
767 n = fread(contents, 1, s * 2, f);
768 fclose(f);
769 if (n == s && memcmp(buff, contents, s) == 0) {
770 free(contents);
771 return (1);
773 failure_start(test_filename, test_line, "File contents don't match");
774 logprintf(" file=\"%s\"\n", fn);
775 if (n > 0)
776 hexdump(contents, buff, n > 512 ? 512 : n, 0);
777 else {
778 logprintf(" File empty, contents should be:\n");
779 hexdump(buff, NULL, s > 512 ? 512 : s, 0);
781 failure_finish(test_extra);
782 free(contents);
783 return (0);
786 /* Check the contents of a text file, being tolerant of line endings. */
788 assertion_text_file_contents(const char *buff, const char *fn)
790 char *contents;
791 const char *btxt, *ftxt;
792 FILE *f;
793 int n, s;
795 assertion_count(test_filename, test_line);
796 f = fopen(fn, "r");
797 s = strlen(buff);
798 contents = malloc(s * 2 + 128);
799 n = fread(contents, 1, s * 2 + 128 - 1, f);
800 if (n >= 0)
801 contents[n] = '\0';
802 fclose(f);
803 /* Compare texts. */
804 btxt = buff;
805 ftxt = (const char *)contents;
806 while (*btxt != '\0' && *ftxt != '\0') {
807 if (*btxt == *ftxt) {
808 ++btxt;
809 ++ftxt;
810 continue;
812 if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') {
813 /* Pass over different new line characters. */
814 ++btxt;
815 ftxt += 2;
816 continue;
818 break;
820 if (*btxt == '\0' && *ftxt == '\0') {
821 free(contents);
822 return (1);
824 failure_start(test_filename, test_line, "Contents don't match");
825 logprintf(" file=\"%s\"\n", fn);
826 if (n > 0)
827 hexdump(contents, buff, n, 0);
828 else {
829 logprintf(" File empty, contents should be:\n");
830 hexdump(buff, NULL, s, 0);
832 failure_finish(test_extra);
833 free(contents);
834 return (0);
837 /* Verify that a text file contains the specified lines, regardless of order */
838 /* This could be more efficient if we sorted both sets of lines, etc, but
839 * since this is used only for testing and only ever deals with a dozen or so
840 * lines at a time, this relatively crude approach is just fine. */
842 assertion_file_contains_lines_any_order(const char *file, int line,
843 const char *pathname, const char *lines[])
845 char *buff;
846 size_t buff_size;
847 size_t expected_count, actual_count, i, j;
848 char **expected;
849 char *p, **actual;
850 char c;
851 int expected_failure = 0, actual_failure = 0;
853 assertion_count(file, line);
855 buff = slurpfile(&buff_size, "%s", pathname);
856 if (buff == NULL) {
857 failure_start(pathname, line, "Can't read file: %s", pathname);
858 failure_finish(NULL);
859 return (0);
862 // Make a copy of the provided lines and count up the expected file size.
863 expected_count = 0;
864 for (i = 0; lines[i] != NULL; ++i) {
866 expected_count = i;
867 expected = malloc(sizeof(char *) * expected_count);
868 for (i = 0; lines[i] != NULL; ++i) {
869 expected[i] = strdup(lines[i]);
872 // Break the file into lines
873 actual_count = 0;
874 for (c = '\0', p = buff; p < buff + buff_size; ++p) {
875 if (*p == '\x0d' || *p == '\x0a')
876 *p = '\0';
877 if (c == '\0' && *p != '\0')
878 ++actual_count;
879 c = *p;
881 actual = malloc(sizeof(char *) * actual_count);
882 for (j = 0, p = buff; p < buff + buff_size; p += 1 + strlen(p)) {
883 if (*p != '\0') {
884 actual[j] = p;
885 ++j;
889 // Erase matching lines from both lists
890 for (i = 0; i < expected_count; ++i) {
891 if (expected[i] == NULL)
892 continue;
893 for (j = 0; j < actual_count; ++j) {
894 if (actual[j] == NULL)
895 continue;
896 if (strcmp(expected[i], actual[j]) == 0) {
897 free(expected[i]);
898 expected[i] = NULL;
899 actual[j] = NULL;
900 break;
905 // If there's anything left, it's a failure
906 for (i = 0; i < expected_count; ++i) {
907 if (expected[i] != NULL)
908 ++expected_failure;
910 for (j = 0; j < actual_count; ++j) {
911 if (actual[j] != NULL)
912 ++actual_failure;
914 if (expected_failure == 0 && actual_failure == 0) {
915 free(buff);
916 free(expected);
917 free(actual);
918 return (1);
920 failure_start(file, line, "File doesn't match: %s", pathname);
921 for (i = 0; i < expected_count; ++i) {
922 if (expected[i] != NULL) {
923 logprintf(" Expected but not present: %s\n", expected[i]);
924 free(expected[i]);
927 for (j = 0; j < actual_count; ++j) {
928 if (actual[j] != NULL)
929 logprintf(" Present but not expected: %s\n", actual[j]);
931 failure_finish(NULL);
932 free(buff);
933 free(expected);
934 free(actual);
935 return (0);
938 /* Test that two paths point to the same file. */
939 /* As a side-effect, asserts that both files exist. */
940 static int
941 is_hardlink(const char *file, int line,
942 const char *path1, const char *path2)
944 #if defined(_WIN32) && !defined(__CYGWIN__)
945 BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
946 int r;
948 assertion_count(file, line);
949 r = my_GetFileInformationByName(path1, &bhfi1);
950 if (r == 0) {
951 failure_start(file, line, "File %s can't be inspected?", path1);
952 failure_finish(NULL);
953 return (0);
955 r = my_GetFileInformationByName(path2, &bhfi2);
956 if (r == 0) {
957 failure_start(file, line, "File %s can't be inspected?", path2);
958 failure_finish(NULL);
959 return (0);
961 return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
962 && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
963 && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow);
964 #else
965 struct stat st1, st2;
966 int r;
968 assertion_count(file, line);
969 r = lstat(path1, &st1);
970 if (r != 0) {
971 failure_start(file, line, "File should exist: %s", path1);
972 failure_finish(NULL);
973 return (0);
975 r = lstat(path2, &st2);
976 if (r != 0) {
977 failure_start(file, line, "File should exist: %s", path2);
978 failure_finish(NULL);
979 return (0);
981 return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
982 #endif
986 assertion_is_hardlink(const char *file, int line,
987 const char *path1, const char *path2)
989 if (is_hardlink(file, line, path1, path2))
990 return (1);
991 failure_start(file, line,
992 "Files %s and %s are not hardlinked", path1, path2);
993 failure_finish(NULL);
994 return (0);
998 assertion_is_not_hardlink(const char *file, int line,
999 const char *path1, const char *path2)
1001 if (!is_hardlink(file, line, path1, path2))
1002 return (1);
1003 failure_start(file, line,
1004 "Files %s and %s should not be hardlinked", path1, path2);
1005 failure_finish(NULL);
1006 return (0);
1009 /* Verify a/b/mtime of 'pathname'. */
1010 /* If 'recent', verify that it's within last 10 seconds. */
1011 static int
1012 assertion_file_time(const char *file, int line,
1013 const char *pathname, long t, long nsec, char type, int recent)
1015 long long filet, filet_nsec;
1016 int r;
1018 #if defined(_WIN32) && !defined(__CYGWIN__)
1019 #define EPOC_TIME (116444736000000000ULL)
1020 FILETIME ftime, fbirthtime, fatime, fmtime;
1021 ULARGE_INTEGER wintm;
1022 HANDLE h;
1023 ftime.dwLowDateTime = 0;
1024 ftime.dwHighDateTime = 0;
1026 assertion_count(file, line);
1027 h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
1028 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1029 if (h == INVALID_HANDLE_VALUE) {
1030 failure_start(file, line, "Can't access %s\n", pathname);
1031 failure_finish(NULL);
1032 return (0);
1034 r = GetFileTime(h, &fbirthtime, &fatime, &fmtime);
1035 switch (type) {
1036 case 'a': ftime = fatime; break;
1037 case 'b': ftime = fbirthtime; break;
1038 case 'm': ftime = fmtime; break;
1040 CloseHandle(h);
1041 if (r == 0) {
1042 failure_start(file, line, "Can't GetFileTime %s\n", pathname);
1043 failure_finish(NULL);
1044 return (0);
1046 wintm.LowPart = ftime.dwLowDateTime;
1047 wintm.HighPart = ftime.dwHighDateTime;
1048 filet = (wintm.QuadPart - EPOC_TIME) / 10000000;
1049 filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100;
1050 nsec = (nsec / 100) * 100; /* Round the request */
1051 #else
1052 struct stat st;
1054 assertion_count(file, line);
1055 r = lstat(pathname, &st);
1056 if (r != 0) {
1057 failure_start(file, line, "Can't stat %s\n", pathname);
1058 failure_finish(NULL);
1059 return (0);
1061 switch (type) {
1062 case 'a': filet = st.st_atime; break;
1063 case 'm': filet = st.st_mtime; break;
1064 case 'b': filet = 0; break;
1065 default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
1066 exit(1);
1068 #if defined(__FreeBSD__)
1069 switch (type) {
1070 case 'a': filet_nsec = st.st_atimespec.tv_nsec; break;
1071 case 'b': filet = st.st_birthtime;
1072 filet_nsec = st.st_birthtimespec.tv_nsec; break;
1073 case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break;
1074 default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
1075 exit(1);
1077 /* FreeBSD generally only stores to microsecond res, so round. */
1078 filet_nsec = (filet_nsec / 1000) * 1000;
1079 nsec = (nsec / 1000) * 1000;
1080 #else
1081 filet_nsec = nsec = 0; /* Generic POSIX only has whole seconds. */
1082 if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */
1083 #if defined(__HAIKU__)
1084 if (type == 'a') return (1); /* Haiku doesn't have atime. */
1085 #endif
1086 #endif
1087 #endif
1088 if (recent) {
1089 /* Check that requested time is up-to-date. */
1090 time_t now = time(NULL);
1091 if (filet < now - 10 || filet > now + 1) {
1092 failure_start(file, line,
1093 "File %s has %ctime %ld, %ld seconds ago\n",
1094 pathname, type, filet, now - filet);
1095 failure_finish(NULL);
1096 return (0);
1098 } else if (filet != t || filet_nsec != nsec) {
1099 failure_start(file, line,
1100 "File %s has %ctime %ld.%09ld, expected %ld.%09ld",
1101 pathname, type, filet, filet_nsec, t, nsec);
1102 failure_finish(NULL);
1103 return (0);
1105 return (1);
1108 /* Verify atime of 'pathname'. */
1110 assertion_file_atime(const char *file, int line,
1111 const char *pathname, long t, long nsec)
1113 return assertion_file_time(file, line, pathname, t, nsec, 'a', 0);
1116 /* Verify atime of 'pathname' is up-to-date. */
1118 assertion_file_atime_recent(const char *file, int line, const char *pathname)
1120 return assertion_file_time(file, line, pathname, 0, 0, 'a', 1);
1123 /* Verify birthtime of 'pathname'. */
1125 assertion_file_birthtime(const char *file, int line,
1126 const char *pathname, long t, long nsec)
1128 return assertion_file_time(file, line, pathname, t, nsec, 'b', 0);
1131 /* Verify birthtime of 'pathname' is up-to-date. */
1133 assertion_file_birthtime_recent(const char *file, int line,
1134 const char *pathname)
1136 return assertion_file_time(file, line, pathname, 0, 0, 'b', 1);
1139 /* Verify mtime of 'pathname'. */
1141 assertion_file_mtime(const char *file, int line,
1142 const char *pathname, long t, long nsec)
1144 return assertion_file_time(file, line, pathname, t, nsec, 'm', 0);
1147 /* Verify mtime of 'pathname' is up-to-date. */
1149 assertion_file_mtime_recent(const char *file, int line, const char *pathname)
1151 return assertion_file_time(file, line, pathname, 0, 0, 'm', 1);
1154 /* Verify number of links to 'pathname'. */
1156 assertion_file_nlinks(const char *file, int line,
1157 const char *pathname, int nlinks)
1159 #if defined(_WIN32) && !defined(__CYGWIN__)
1160 BY_HANDLE_FILE_INFORMATION bhfi;
1161 int r;
1163 assertion_count(file, line);
1164 r = my_GetFileInformationByName(pathname, &bhfi);
1165 if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks)
1166 return (1);
1167 failure_start(file, line, "File %s has %d links, expected %d",
1168 pathname, bhfi.nNumberOfLinks, nlinks);
1169 failure_finish(NULL);
1170 return (0);
1171 #else
1172 struct stat st;
1173 int r;
1175 assertion_count(file, line);
1176 r = lstat(pathname, &st);
1177 if (r == 0 && st.st_nlink == nlinks)
1178 return (1);
1179 failure_start(file, line, "File %s has %d links, expected %d",
1180 pathname, st.st_nlink, nlinks);
1181 failure_finish(NULL);
1182 return (0);
1183 #endif
1186 /* Verify size of 'pathname'. */
1188 assertion_file_size(const char *file, int line, const char *pathname, long size)
1190 int64_t filesize;
1191 int r;
1193 assertion_count(file, line);
1194 #if defined(_WIN32) && !defined(__CYGWIN__)
1196 BY_HANDLE_FILE_INFORMATION bhfi;
1197 r = !my_GetFileInformationByName(pathname, &bhfi);
1198 filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow;
1200 #else
1202 struct stat st;
1203 r = lstat(pathname, &st);
1204 filesize = st.st_size;
1206 #endif
1207 if (r == 0 && filesize == size)
1208 return (1);
1209 failure_start(file, line, "File %s has size %ld, expected %ld",
1210 pathname, (long)filesize, (long)size);
1211 failure_finish(NULL);
1212 return (0);
1215 /* Assert that 'pathname' is a dir. If mode >= 0, verify that too. */
1217 assertion_is_dir(const char *file, int line, const char *pathname, int mode)
1219 struct stat st;
1220 int r;
1222 #if defined(_WIN32) && !defined(__CYGWIN__)
1223 (void)mode; /* UNUSED */
1224 #endif
1225 assertion_count(file, line);
1226 r = lstat(pathname, &st);
1227 if (r != 0) {
1228 failure_start(file, line, "Dir should exist: %s", pathname);
1229 failure_finish(NULL);
1230 return (0);
1232 if (!S_ISDIR(st.st_mode)) {
1233 failure_start(file, line, "%s is not a dir", pathname);
1234 failure_finish(NULL);
1235 return (0);
1237 #if !defined(_WIN32) || defined(__CYGWIN__)
1238 /* Windows doesn't handle permissions the same way as POSIX,
1239 * so just ignore the mode tests. */
1240 /* TODO: Can we do better here? */
1241 if (mode >= 0 && mode != (st.st_mode & 07777)) {
1242 failure_start(file, line, "Dir %s has wrong mode", pathname);
1243 logprintf(" Expected: 0%3o\n", mode);
1244 logprintf(" Found: 0%3o\n", st.st_mode & 07777);
1245 failure_finish(NULL);
1246 return (0);
1248 #endif
1249 return (1);
1252 /* Verify that 'pathname' is a regular file. If 'mode' is >= 0,
1253 * verify that too. */
1255 assertion_is_reg(const char *file, int line, const char *pathname, int mode)
1257 struct stat st;
1258 int r;
1260 #if defined(_WIN32) && !defined(__CYGWIN__)
1261 (void)mode; /* UNUSED */
1262 #endif
1263 assertion_count(file, line);
1264 r = lstat(pathname, &st);
1265 if (r != 0 || !S_ISREG(st.st_mode)) {
1266 failure_start(file, line, "File should exist: %s", pathname);
1267 failure_finish(NULL);
1268 return (0);
1270 #if !defined(_WIN32) || defined(__CYGWIN__)
1271 /* Windows doesn't handle permissions the same way as POSIX,
1272 * so just ignore the mode tests. */
1273 /* TODO: Can we do better here? */
1274 if (mode >= 0 && mode != (st.st_mode & 07777)) {
1275 failure_start(file, line, "File %s has wrong mode", pathname);
1276 logprintf(" Expected: 0%3o\n", mode);
1277 logprintf(" Found: 0%3o\n", st.st_mode & 07777);
1278 failure_finish(NULL);
1279 return (0);
1281 #endif
1282 return (1);
1285 /* Check whether 'pathname' is a symbolic link. If 'contents' is
1286 * non-NULL, verify that the symlink has those contents. */
1287 static int
1288 is_symlink(const char *file, int line,
1289 const char *pathname, const char *contents)
1291 #if defined(_WIN32) && !defined(__CYGWIN__)
1292 (void)pathname; /* UNUSED */
1293 (void)contents; /* UNUSED */
1294 assertion_count(file, line);
1295 /* Windows sort-of has real symlinks, but they're only usable
1296 * by privileged users and are crippled even then, so there's
1297 * really not much point in bothering with this. */
1298 return (0);
1299 #else
1300 char buff[300];
1301 struct stat st;
1302 ssize_t linklen;
1303 int r;
1305 assertion_count(file, line);
1306 r = lstat(pathname, &st);
1307 if (r != 0) {
1308 failure_start(file, line,
1309 "Symlink should exist: %s", pathname);
1310 failure_finish(NULL);
1311 return (0);
1313 if (!S_ISLNK(st.st_mode))
1314 return (0);
1315 if (contents == NULL)
1316 return (1);
1317 linklen = readlink(pathname, buff, sizeof(buff));
1318 if (linklen < 0) {
1319 failure_start(file, line, "Can't read symlink %s", pathname);
1320 failure_finish(NULL);
1321 return (0);
1323 buff[linklen] = '\0';
1324 if (strcmp(buff, contents) != 0)
1325 return (0);
1326 return (1);
1327 #endif
1330 /* Assert that path is a symlink that (optionally) contains contents. */
1332 assertion_is_symlink(const char *file, int line,
1333 const char *path, const char *contents)
1335 if (is_symlink(file, line, path, contents))
1336 return (1);
1337 if (contents)
1338 failure_start(file, line, "File %s is not a symlink to %s",
1339 path, contents);
1340 else
1341 failure_start(file, line, "File %s is not a symlink", path);
1342 failure_finish(NULL);
1343 return (0);
1347 /* Create a directory and report any errors. */
1349 assertion_make_dir(const char *file, int line, const char *dirname, int mode)
1351 assertion_count(file, line);
1352 #if defined(_WIN32) && !defined(__CYGWIN__)
1353 (void)mode; /* UNUSED */
1354 if (0 == _mkdir(dirname))
1355 return (1);
1356 #else
1357 if (0 == mkdir(dirname, mode))
1358 return (1);
1359 #endif
1360 failure_start(file, line, "Could not create directory %s", dirname);
1361 failure_finish(NULL);
1362 return(0);
1365 /* Create a file with the specified contents and report any failures. */
1367 assertion_make_file(const char *file, int line,
1368 const char *path, int mode, const char *contents)
1370 #if defined(_WIN32) && !defined(__CYGWIN__)
1371 /* TODO: Rework this to set file mode as well. */
1372 FILE *f;
1373 (void)mode; /* UNUSED */
1374 assertion_count(file, line);
1375 f = fopen(path, "wb");
1376 if (f == NULL) {
1377 failure_start(file, line, "Could not create file %s", path);
1378 failure_finish(NULL);
1379 return (0);
1381 if (contents != NULL) {
1382 if (strlen(contents)
1383 != fwrite(contents, 1, strlen(contents), f)) {
1384 fclose(f);
1385 failure_start(file, line,
1386 "Could not write file %s", path);
1387 failure_finish(NULL);
1388 return (0);
1391 fclose(f);
1392 return (1);
1393 #else
1394 int fd;
1395 assertion_count(file, line);
1396 fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644);
1397 if (fd < 0) {
1398 failure_start(file, line, "Could not create %s", path);
1399 failure_finish(NULL);
1400 return (0);
1402 if (contents != NULL) {
1403 if ((ssize_t)strlen(contents)
1404 != write(fd, contents, strlen(contents))) {
1405 close(fd);
1406 failure_start(file, line, "Could not write to %s", path);
1407 failure_finish(NULL);
1408 return (0);
1411 close(fd);
1412 return (1);
1413 #endif
1416 /* Create a hardlink and report any failures. */
1418 assertion_make_hardlink(const char *file, int line,
1419 const char *newpath, const char *linkto)
1421 int succeeded;
1423 assertion_count(file, line);
1424 #if defined(_WIN32) && !defined(__CYGWIN__)
1425 succeeded = my_CreateHardLinkA(newpath, linkto);
1426 #elif HAVE_LINK
1427 succeeded = !link(linkto, newpath);
1428 #else
1429 succeeded = 0;
1430 #endif
1431 if (succeeded)
1432 return (1);
1433 failure_start(file, line, "Could not create hardlink");
1434 logprintf(" New link: %s\n", newpath);
1435 logprintf(" Old name: %s\n", linkto);
1436 failure_finish(NULL);
1437 return(0);
1440 /* Create a symlink and report any failures. */
1442 assertion_make_symlink(const char *file, int line,
1443 const char *newpath, const char *linkto)
1445 #if defined(_WIN32) && !defined(__CYGWIN__)
1446 int targetIsDir = 0; /* TODO: Fix this */
1447 assertion_count(file, line);
1448 if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir))
1449 return (1);
1450 #elif HAVE_SYMLINK
1451 assertion_count(file, line);
1452 if (0 == symlink(linkto, newpath))
1453 return (1);
1454 #endif
1455 failure_start(file, line, "Could not create symlink");
1456 logprintf(" New link: %s\n", newpath);
1457 logprintf(" Old name: %s\n", linkto);
1458 failure_finish(NULL);
1459 return(0);
1462 /* Set umask, report failures. */
1464 assertion_umask(const char *file, int line, int mask)
1466 assertion_count(file, line);
1467 (void)file; /* UNUSED */
1468 (void)line; /* UNUSED */
1469 umask(mask);
1470 return (1);
1475 * UTILITIES for use by tests.
1480 * Check whether platform supports symlinks. This is intended
1481 * for tests to use in deciding whether to bother testing symlink
1482 * support; if the platform doesn't support symlinks, there's no point
1483 * in checking whether the program being tested can create them.
1485 * Note that the first time this test is called, we actually go out to
1486 * disk to create and verify a symlink. This is necessary because
1487 * symlink support is actually a property of a particular filesystem
1488 * and can thus vary between directories on a single system. After
1489 * the first call, this returns the cached result from memory, so it's
1490 * safe to call it as often as you wish.
1493 canSymlink(void)
1495 /* Remember the test result */
1496 static int value = 0, tested = 0;
1497 if (tested)
1498 return (value);
1500 ++tested;
1501 assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, "a");
1502 /* Note: Cygwin has its own symlink() emulation that does not
1503 * use the Win32 CreateSymbolicLink() function. */
1504 #if defined(_WIN32) && !defined(__CYGWIN__)
1505 value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
1506 && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
1507 #elif HAVE_SYMLINK
1508 value = (0 == symlink("canSymlink.0", "canSymlink.1"))
1509 && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
1510 #endif
1511 return (value);
1515 * Can this platform run the gzip program?
1517 /* Platform-dependent options for hiding the output of a subcommand. */
1518 #if defined(_WIN32) && !defined(__CYGWIN__)
1519 static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
1520 #else
1521 static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
1522 #endif
1524 canGzip(void)
1526 static int tested = 0, value = 0;
1527 if (!tested) {
1528 tested = 1;
1529 if (systemf("gzip -V %s", redirectArgs) == 0)
1530 value = 1;
1532 return (value);
1536 * Can this platform run the gunzip program?
1539 canGunzip(void)
1541 static int tested = 0, value = 0;
1542 if (!tested) {
1543 tested = 1;
1544 if (systemf("gunzip -V %s", redirectArgs) == 0)
1545 value = 1;
1547 return (value);
1551 * Sleep as needed; useful for verifying disk timestamp changes by
1552 * ensuring that the wall-clock time has actually changed before we
1553 * go back to re-read something from disk.
1555 void
1556 sleepUntilAfter(time_t t)
1558 while (t >= time(NULL))
1559 #if defined(_WIN32) && !defined(__CYGWIN__)
1560 Sleep(500);
1561 #else
1562 sleep(1);
1563 #endif
1567 * Call standard system() call, but build up the command line using
1568 * sprintf() conventions.
1571 systemf(const char *fmt, ...)
1573 char buff[8192];
1574 va_list ap;
1575 int r;
1577 va_start(ap, fmt);
1578 vsprintf(buff, fmt, ap);
1579 if (verbosity > VERBOSITY_FULL)
1580 logprintf("Cmd: %s\n", buff);
1581 r = system(buff);
1582 va_end(ap);
1583 return (r);
1587 * Slurp a file into memory for ease of comparison and testing.
1588 * Returns size of file in 'sizep' if non-NULL, null-terminates
1589 * data in memory for ease of use.
1591 char *
1592 slurpfile(size_t * sizep, const char *fmt, ...)
1594 char filename[8192];
1595 struct stat st;
1596 va_list ap;
1597 char *p;
1598 ssize_t bytes_read;
1599 FILE *f;
1600 int r;
1602 va_start(ap, fmt);
1603 vsprintf(filename, fmt, ap);
1604 va_end(ap);
1606 f = fopen(filename, "rb");
1607 if (f == NULL) {
1608 /* Note: No error; non-existent file is okay here. */
1609 return (NULL);
1611 r = fstat(fileno(f), &st);
1612 if (r != 0) {
1613 logprintf("Can't stat file %s\n", filename);
1614 fclose(f);
1615 return (NULL);
1617 p = malloc((size_t)st.st_size + 1);
1618 if (p == NULL) {
1619 logprintf("Can't allocate %ld bytes of memory to read file %s\n",
1620 (long int)st.st_size, filename);
1621 fclose(f);
1622 return (NULL);
1624 bytes_read = fread(p, 1, (size_t)st.st_size, f);
1625 if (bytes_read < st.st_size) {
1626 logprintf("Can't read file %s\n", filename);
1627 fclose(f);
1628 free(p);
1629 return (NULL);
1631 p[st.st_size] = '\0';
1632 if (sizep != NULL)
1633 *sizep = (size_t)st.st_size;
1634 fclose(f);
1635 return (p);
1638 /* Read a uuencoded file from the reference directory, decode, and
1639 * write the result into the current directory. */
1640 #define UUDECODE(c) (((c) - 0x20) & 0x3f)
1641 void
1642 extract_reference_file(const char *name)
1644 char buff[1024];
1645 FILE *in, *out;
1647 sprintf(buff, "%s/%s.uu", refdir, name);
1648 in = fopen(buff, "r");
1649 failure("Couldn't open reference file %s", buff);
1650 assert(in != NULL);
1651 if (in == NULL)
1652 return;
1653 /* Read up to and including the 'begin' line. */
1654 for (;;) {
1655 if (fgets(buff, sizeof(buff), in) == NULL) {
1656 /* TODO: This is a failure. */
1657 return;
1659 if (memcmp(buff, "begin ", 6) == 0)
1660 break;
1662 /* Now, decode the rest and write it. */
1663 /* Not a lot of error checking here; the input better be right. */
1664 out = fopen(name, "wb");
1665 while (fgets(buff, sizeof(buff), in) != NULL) {
1666 char *p = buff;
1667 int bytes;
1669 if (memcmp(buff, "end", 3) == 0)
1670 break;
1672 bytes = UUDECODE(*p++);
1673 while (bytes > 0) {
1674 int n = 0;
1675 /* Write out 1-3 bytes from that. */
1676 if (bytes > 0) {
1677 n = UUDECODE(*p++) << 18;
1678 n |= UUDECODE(*p++) << 12;
1679 fputc(n >> 16, out);
1680 --bytes;
1682 if (bytes > 0) {
1683 n |= UUDECODE(*p++) << 6;
1684 fputc((n >> 8) & 0xFF, out);
1685 --bytes;
1687 if (bytes > 0) {
1688 n |= UUDECODE(*p++);
1689 fputc(n & 0xFF, out);
1690 --bytes;
1694 fclose(out);
1695 fclose(in);
1700 * TEST management
1705 * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has
1706 * a line like
1707 * DEFINE_TEST(test_function)
1708 * for each test.
1711 /* Use "list.h" to declare all of the test functions. */
1712 #undef DEFINE_TEST
1713 #define DEFINE_TEST(name) void name(void);
1714 #include "list.h"
1716 /* Use "list.h" to create a list of all tests (functions and names). */
1717 #undef DEFINE_TEST
1718 #define DEFINE_TEST(n) { n, #n, 0 },
1719 struct { void (*func)(void); const char *name; int failures; } tests[] = {
1720 #include "list.h"
1724 * Summarize repeated failures in the just-completed test.
1726 static void
1727 test_summarize(const char *filename, int failed)
1729 unsigned int i;
1731 switch (verbosity) {
1732 case VERBOSITY_SUMMARY_ONLY:
1733 printf(failed ? "E" : ".");
1734 fflush(stdout);
1735 break;
1736 case VERBOSITY_PASSFAIL:
1737 printf(failed ? "FAIL\n" : "ok\n");
1738 break;
1741 log_console = (verbosity == VERBOSITY_LIGHT_REPORT);
1743 for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) {
1744 if (failed_lines[i].count > 1 && !failed_lines[i].skip)
1745 logprintf("%s:%d: Summary: Failed %d times\n",
1746 filename, i, failed_lines[i].count);
1748 /* Clear the failure history for the next file. */
1749 memset(failed_lines, 0, sizeof(failed_lines));
1753 * Actually run a single test, with appropriate setup and cleanup.
1755 static int
1756 test_run(int i, const char *tmpdir)
1758 char logfilename[64];
1759 int failures_before = failures;
1760 int oldumask;
1762 switch (verbosity) {
1763 case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */
1764 break;
1765 case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */
1766 printf("%3d: %-50s", i, tests[i].name);
1767 fflush(stdout);
1768 break;
1769 default: /* Title of test, details will follow */
1770 printf("%3d: %s\n", i, tests[i].name);
1773 /* Chdir to the top-level work directory. */
1774 if (!assertChdir(tmpdir)) {
1775 fprintf(stderr,
1776 "ERROR: Can't chdir to top work dir %s\n", tmpdir);
1777 exit(1);
1779 /* Create a log file for this test. */
1780 sprintf(logfilename, "%s.log", tests[i].name);
1781 logfile = fopen(logfilename, "w");
1782 fprintf(logfile, "%s\n\n", tests[i].name);
1783 /* Chdir() to a work dir for this specific test. */
1784 if (!assertMakeDir(tests[i].name, 0755)
1785 || !assertChdir(tests[i].name)) {
1786 fprintf(stderr,
1787 "ERROR: Can't chdir to work dir %s/%s\n",
1788 tmpdir, tests[i].name);
1789 exit(1);
1791 /* Explicitly reset the locale before each test. */
1792 setlocale(LC_ALL, "C");
1793 /* Record the umask before we run the test. */
1794 umask(oldumask = umask(0));
1796 * Run the actual test.
1798 (*tests[i].func)();
1800 * Clean up and report afterwards.
1802 /* Restore umask */
1803 umask(oldumask);
1804 /* Reset locale. */
1805 setlocale(LC_ALL, "C");
1806 /* Reset directory. */
1807 if (!assertChdir(tmpdir)) {
1808 fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n",
1809 tmpdir);
1810 exit(1);
1812 /* Report per-test summaries. */
1813 tests[i].failures = failures - failures_before;
1814 test_summarize(test_filename, tests[i].failures);
1815 /* Close the per-test log file. */
1816 fclose(logfile);
1817 logfile = NULL;
1818 /* If there were no failures, we can remove the work dir and logfile. */
1819 if (tests[i].failures == 0) {
1820 if (!keep_temp_files && assertChdir(tmpdir)) {
1821 #if defined(_WIN32) && !defined(__CYGWIN__)
1822 /* Make sure not to leave empty directories.
1823 * Sometimes a processing of closing files used by tests
1824 * is not done, then rmdir will be failed and it will
1825 * leave a empty test directory. So we should wait a few
1826 * seconds and retry rmdir. */
1827 int r, t;
1828 for (t = 0; t < 10; t++) {
1829 if (t > 0)
1830 Sleep(1000);
1831 r = systemf("rmdir /S /Q %s", tests[i].name);
1832 if (r == 0)
1833 break;
1835 systemf("del %s", logfilename);
1836 #else
1837 systemf("rm -rf %s", tests[i].name);
1838 systemf("rm %s", logfilename);
1839 #endif
1842 /* Return appropriate status. */
1843 return (tests[i].failures);
1849 * MAIN and support routines.
1854 static void
1855 usage(const char *program)
1857 static const int limit = sizeof(tests) / sizeof(tests[0]);
1858 int i;
1860 printf("Usage: %s [options] <test> <test> ...\n", program);
1861 printf("Default is to run all tests.\n");
1862 printf("Otherwise, specify the numbers of the tests you wish to run.\n");
1863 printf("Options:\n");
1864 printf(" -d Dump core after any failure, for debugging.\n");
1865 printf(" -k Keep all temp files.\n");
1866 printf(" Default: temp files for successful tests deleted.\n");
1867 #ifdef PROGRAM
1868 printf(" -p <path> Path to executable to be tested.\n");
1869 printf(" Default: path taken from " ENVBASE " environment variable.\n");
1870 #endif
1871 printf(" -q Quiet.\n");
1872 printf(" -r <dir> Path to dir containing reference files.\n");
1873 printf(" Default: Current directory.\n");
1874 printf(" -v Verbose.\n");
1875 printf("Available tests:\n");
1876 for (i = 0; i < limit; i++)
1877 printf(" %d: %s\n", i, tests[i].name);
1878 exit(1);
1881 static char *
1882 get_refdir(const char *d)
1884 char tried[512] = { '\0' };
1885 char buff[128];
1886 char *pwd, *p;
1888 /* If a dir was specified, try that */
1889 if (d != NULL) {
1890 pwd = NULL;
1891 snprintf(buff, sizeof(buff), "%s", d);
1892 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
1893 if (p != NULL) goto success;
1894 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
1895 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
1896 goto failure;
1899 /* Get the current dir. */
1900 pwd = getcwd(NULL, 0);
1901 while (pwd[strlen(pwd) - 1] == '\n')
1902 pwd[strlen(pwd) - 1] = '\0';
1904 /* Look for a known file. */
1905 snprintf(buff, sizeof(buff), "%s", pwd);
1906 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
1907 if (p != NULL) goto success;
1908 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
1909 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
1911 snprintf(buff, sizeof(buff), "%s/test", pwd);
1912 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
1913 if (p != NULL) goto success;
1914 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
1915 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
1917 #if defined(LIBRARY)
1918 snprintf(buff, sizeof(buff), "%s/%s/test", pwd, LIBRARY);
1919 #else
1920 snprintf(buff, sizeof(buff), "%s/%s/test", pwd, PROGRAM);
1921 #endif
1922 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
1923 if (p != NULL) goto success;
1924 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
1925 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
1927 if (memcmp(pwd, "/usr/obj", 8) == 0) {
1928 snprintf(buff, sizeof(buff), "%s", pwd + 8);
1929 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
1930 if (p != NULL) goto success;
1931 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
1932 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
1934 snprintf(buff, sizeof(buff), "%s/test", pwd + 8);
1935 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
1936 if (p != NULL) goto success;
1937 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
1938 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
1941 failure:
1942 printf("Unable to locate known reference file %s\n", KNOWNREF);
1943 printf(" Checked following directories:\n%s\n", tried);
1944 #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
1945 DebugBreak();
1946 #endif
1947 exit(1);
1949 success:
1950 free(p);
1951 free(pwd);
1952 return strdup(buff);
1956 main(int argc, char **argv)
1958 static const int limit = sizeof(tests) / sizeof(tests[0]);
1959 int i, tests_run = 0, tests_failed = 0, option;
1960 time_t now;
1961 char *refdir_alloc = NULL;
1962 const char *progname;
1963 const char *tmp, *option_arg, *p;
1964 char tmpdir[256];
1965 char tmpdir_timestamp[256];
1967 (void)argc; /* UNUSED */
1969 #if defined(HAVE__CrtSetReportMode)
1970 /* To stop to run the default invalid parameter handler. */
1971 _set_invalid_parameter_handler(invalid_parameter_handler);
1972 /* Disable annoying assertion message box. */
1973 _CrtSetReportMode(_CRT_ASSERT, 0);
1974 #endif
1977 * Name of this program, used to build root of our temp directory
1978 * tree.
1980 progname = p = argv[0];
1981 while (*p != '\0') {
1982 /* Support \ or / dir separators for Windows compat. */
1983 if (*p == '/' || *p == '\\')
1984 progname = p + 1;
1985 ++p;
1988 #ifdef PROGRAM
1989 /* Get the target program from environment, if available. */
1990 testprogfile = getenv(ENVBASE);
1991 #endif
1993 if (getenv("TMPDIR") != NULL)
1994 tmp = getenv("TMPDIR");
1995 else if (getenv("TMP") != NULL)
1996 tmp = getenv("TMP");
1997 else if (getenv("TEMP") != NULL)
1998 tmp = getenv("TEMP");
1999 else if (getenv("TEMPDIR") != NULL)
2000 tmp = getenv("TEMPDIR");
2001 else
2002 tmp = "/tmp";
2004 /* Allow -d to be controlled through the environment. */
2005 if (getenv(ENVBASE "_DEBUG") != NULL)
2006 dump_on_failure = 1;
2008 /* Get the directory holding test files from environment. */
2009 refdir = getenv(ENVBASE "_TEST_FILES");
2012 * Parse options, without using getopt(), which isn't available
2013 * on all platforms.
2015 ++argv; /* Skip program name */
2016 while (*argv != NULL) {
2017 if (**argv != '-')
2018 break;
2019 p = *argv++;
2020 ++p; /* Skip '-' */
2021 while (*p != '\0') {
2022 option = *p++;
2023 option_arg = NULL;
2024 /* If 'opt' takes an argument, parse that. */
2025 if (option == 'p' || option == 'r') {
2026 if (*p != '\0')
2027 option_arg = p;
2028 else if (*argv == NULL) {
2029 fprintf(stderr,
2030 "Option -%c requires argument.\n",
2031 option);
2032 usage(progname);
2033 } else
2034 option_arg = *argv++;
2035 p = ""; /* End of this option word. */
2038 /* Now, handle the option. */
2039 switch (option) {
2040 case 'd':
2041 dump_on_failure = 1;
2042 break;
2043 case 'k':
2044 keep_temp_files = 1;
2045 break;
2046 case 'p':
2047 #ifdef PROGRAM
2048 testprogfile = option_arg;
2049 #else
2050 fprintf(stderr, "-p option not permitted\n");
2051 usage(progname);
2052 #endif
2053 break;
2054 case 'q':
2055 verbosity--;
2056 break;
2057 case 'r':
2058 refdir = option_arg;
2059 break;
2060 case 'v':
2061 verbosity++;
2062 break;
2063 default:
2064 fprintf(stderr, "Unrecognized option '%c'\n",
2065 option);
2066 usage(progname);
2072 * Sanity-check that our options make sense.
2074 #ifdef PROGRAM
2075 if (testprogfile == NULL) {
2076 fprintf(stderr, "Program executable required\n");
2077 usage(progname);
2081 char *testprg;
2082 #if defined(_WIN32) && !defined(__CYGWIN__)
2083 /* Command.com sometimes rejects '/' separators. */
2084 testprg = strdup(testprogfile);
2085 for (i = 0; testprg[i] != '\0'; i++) {
2086 if (testprg[i] == '/')
2087 testprg[i] = '\\';
2089 testprogfile = testprg;
2090 #endif
2091 /* Quote the name that gets put into shell command lines. */
2092 testprg = malloc(strlen(testprogfile) + 3);
2093 strcpy(testprg, "\"");
2094 strcat(testprg, testprogfile);
2095 strcat(testprg, "\"");
2096 testprog = testprg;
2098 #endif
2101 * Create a temp directory for the following tests.
2102 * Include the time the tests started as part of the name,
2103 * to make it easier to track the results of multiple tests.
2105 now = time(NULL);
2106 for (i = 0; ; i++) {
2107 strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp),
2108 "%Y-%m-%dT%H.%M.%S",
2109 localtime(&now));
2110 sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname,
2111 tmpdir_timestamp, i);
2112 if (assertMakeDir(tmpdir,0755))
2113 break;
2114 if (i >= 999) {
2115 fprintf(stderr,
2116 "ERROR: Unable to create temp directory %s\n",
2117 tmpdir);
2118 exit(1);
2123 * If the user didn't specify a directory for locating
2124 * reference files, try to find the reference files in
2125 * the "usual places."
2127 refdir = refdir_alloc = get_refdir(refdir);
2130 * Banner with basic information.
2132 printf("\n");
2133 printf("If tests fail or crash, details will be in:\n");
2134 printf(" %s\n", tmpdir);
2135 printf("\n");
2136 if (verbosity > VERBOSITY_SUMMARY_ONLY) {
2137 printf("Reference files will be read from: %s\n", refdir);
2138 #ifdef PROGRAM
2139 printf("Running tests on: %s\n", testprog);
2140 #endif
2141 printf("Exercising: ");
2142 fflush(stdout);
2143 printf("%s\n", EXTRA_VERSION);
2144 } else {
2145 printf("Running ");
2146 fflush(stdout);
2150 * Run some or all of the individual tests.
2152 if (*argv == NULL) {
2153 /* Default: Run all tests. */
2154 for (i = 0; i < limit; i++) {
2155 if (test_run(i, tmpdir))
2156 tests_failed++;
2157 tests_run++;
2159 } else {
2160 while (*(argv) != NULL) {
2161 if (**argv >= '0' && **argv <= '9') {
2162 i = atoi(*argv);
2163 if (i < 0 || i >= limit) {
2164 printf("*** INVALID Test %s\n", *argv);
2165 free(refdir_alloc);
2166 usage(progname);
2167 /* usage() never returns */
2169 } else {
2170 for (i = 0; i < limit; ++i) {
2171 if (strcmp(*argv, tests[i].name) == 0)
2172 break;
2174 if (i >= limit) {
2175 printf("*** INVALID Test ``%s''\n",
2176 *argv);
2177 free(refdir_alloc);
2178 usage(progname);
2179 /* usage() never returns */
2182 if (test_run(i, tmpdir))
2183 tests_failed++;
2184 tests_run++;
2185 argv++;
2190 * Report summary statistics.
2192 if (verbosity > VERBOSITY_SUMMARY_ONLY) {
2193 printf("\n");
2194 printf("Totals:\n");
2195 printf(" Tests run: %8d\n", tests_run);
2196 printf(" Tests failed: %8d\n", tests_failed);
2197 printf(" Assertions checked:%8d\n", assertions);
2198 printf(" Assertions failed: %8d\n", failures);
2199 printf(" Skips reported: %8d\n", skips);
2201 if (failures) {
2202 printf("\n");
2203 printf("Failing tests:\n");
2204 for (i = 0; i < limit; ++i) {
2205 if (tests[i].failures)
2206 printf(" %d: %s (%d failures)\n", i,
2207 tests[i].name, tests[i].failures);
2209 printf("\n");
2210 printf("Details for failing tests: %s\n", tmpdir);
2211 printf("\n");
2212 } else {
2213 if (verbosity == VERBOSITY_SUMMARY_ONLY)
2214 printf("\n");
2215 printf("%d tests passed, no failures\n", tests_run);
2218 free(refdir_alloc);
2220 /* If the final tmpdir is empty, we can remove it. */
2221 /* This should be the usual case when all tests succeed. */
2222 assertChdir("..");
2223 rmdir(tmpdir);
2225 return (tests_failed ? 1 : 0);