2 * Copyright (c) 2003-2007 Tim Kientzle
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
27 * Various utility routines useful for test programs.
28 * Each test program is linked against this file.
36 #if defined(_WIN32) && !defined(__CYGWIN__)
43 * This same file is used pretty much verbatim for all test harnesses.
45 * The next few lines are the only differences.
47 #undef PROGRAM /* Testing a library, not a program. */
48 #define LIBRARY "libarchive"
49 #define ENVBASE "LIBARCHIVE" /* Prefix for environment variables. */
50 #define EXTRA_DUMP(x) archive_error_string((struct archive *)(x))
51 #define EXTRA_VERSION archive_version()
52 #define KNOWNREF "test_compat_gtar_1.tar.uu"
53 __FBSDID("$FreeBSD$");
56 * "list.h" is simply created by "grep DEFINE_TEST"; it has
58 * DEFINE_TEST(test_function)
60 * Include it here with a suitable DEFINE_TEST to declare all of the
64 #define DEFINE_TEST(name) void name(void);
67 /* Interix doesn't define these in a standard header. */
73 /* Enable core dump on failure. */
74 static int dump_on_failure = 0;
75 /* Default is to remove temp dirs for successful tests. */
76 static int keep_temp_files = 0;
77 /* Default is to print some basic information about each test. */
78 static int quiet_flag = 0;
79 /* Default is to summarize repeated failures. */
80 static int verbose = 0;
81 /* Cumulative count of component failures. */
82 static int failures = 0;
83 /* Cumulative count of skipped component tests. */
85 /* Cumulative count of assertions. */
86 static int assertions = 0;
88 /* Directory where uuencoded reference files can be found. */
89 static const char *refdir;
92 #if defined(_WIN32) && !defined(__CYGWIN__)
95 invalid_parameter_handler(const wchar_t * expression,
96 const wchar_t * function, const wchar_t * file,
97 unsigned int line, uintptr_t pReserved)
105 * My own implementation of the standard assert() macro emits the
106 * message in the same format as GCC (file:line: message).
107 * It also includes some additional useful information.
108 * This makes it a lot easier to skim through test failures in
111 * It also supports a few special features specifically to simplify
113 * failure(fmt, args) -- Stores a text string that gets
114 * printed if the following assertion fails, good for
115 * explaining subtle tests.
117 static char msg[4096];
120 * For each test source file, we remember how many times each
121 * failure was reported.
123 static const char *failed_filename = NULL;
128 } failed_lines[1000];
131 * Called at the beginning of each assert() function.
134 count_assertion(const char *file, int line)
136 (void)file; /* UNUSED */
137 (void)line; /* UNUSED */
139 /* Uncomment to print file:line after every assertion.
140 * Verbose, but occasionally useful in tracking down crashes. */
141 /* printf("Checked %s:%d\n", file, line); */
145 * Count this failure; return the number of previous failures.
148 previous_failures(const char *filename, int line, int critical)
153 if (failed_filename == NULL || strcmp(failed_filename, filename) != 0)
154 memset(failed_lines, 0, sizeof(failed_lines));
155 failed_filename = filename;
157 for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) {
158 if (failed_lines[i].line == line) {
159 count = failed_lines[i].count;
160 failed_lines[i].count++;
163 if (failed_lines[i].line == 0) {
164 failed_lines[i].line = line;
165 failed_lines[i].count = 1;
166 failed_lines[i].critical = critical;
174 * Copy arguments into file-local variables.
176 static const char *test_filename;
177 static int test_line;
178 static void *test_extra;
179 void test_setup(const char *filename, int line)
181 test_filename = filename;
186 * Inform user that we're skipping a test.
189 test_skipping(const char *fmt, ...)
193 if (previous_failures(test_filename, test_line, 0))
197 fprintf(stderr, " *** SKIPPING: ");
198 vfprintf(stderr, fmt, ap);
199 fprintf(stderr, "\n");
204 /* Common handling of failed tests. */
206 report_failure(void *extra)
208 if (msg[0] != '\0') {
209 fprintf(stderr, " Description: %s\n", msg);
215 fprintf(stderr, " detail: %s\n", EXTRA_DUMP(extra));
217 (void)extra; /* UNUSED */
220 if (dump_on_failure) {
222 " *** forcing core dump so failure can be debugged ***\n");
229 * Summarize repeated failures in the just-completed test file.
230 * The reports above suppress multiple failures from the same source
231 * line; this reports on any tests that did fail multiple times.
234 summarize_comparator(const void *a0, const void *b0)
236 const struct line *a = a0, *b = b0;
237 if (a->line == 0 && b->line == 0)
243 return (a->line - b->line);
251 qsort(failed_lines, sizeof(failed_lines)/sizeof(failed_lines[0]),
252 sizeof(failed_lines[0]), summarize_comparator);
253 for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) {
254 if (failed_lines[i].line == 0)
256 if (failed_lines[i].count > 1 && failed_lines[i].critical)
257 fprintf(stderr, "%s:%d: Failed %d times\n",
258 failed_filename, failed_lines[i].line,
259 failed_lines[i].count);
261 /* Clear the failure history for the next file. */
262 memset(failed_lines, 0, sizeof(failed_lines));
265 /* Set up a message to display only after a test fails. */
267 failure(const char *fmt, ...)
271 vsprintf(msg, fmt, ap);
275 /* Generic assert() just displays the failed condition. */
277 test_assert(const char *file, int line, int value, const char *condition, void *extra)
279 count_assertion(file, line);
285 if (!verbose && previous_failures(file, line, 1))
287 fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
288 fprintf(stderr, " Condition: %s\n", condition);
289 report_failure(extra);
293 /* assertEqualInt() displays the values of the two integers. */
295 test_assert_equal_int(const char *file, int line,
296 int v1, const char *e1, int v2, const char *e2, void *extra)
298 count_assertion(file, line);
304 if (!verbose && previous_failures(file, line, 1))
306 fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n",
308 fprintf(stderr, " %s=%d\n", e1, v1);
309 fprintf(stderr, " %s=%d\n", e2, v2);
310 report_failure(extra);
314 static void strdump(const char *p)
317 fprintf(stderr, "(null)");
320 fprintf(stderr, "\"");
322 unsigned int c = 0xff & *p++;
324 case '\a': fprintf(stderr, "\a"); break;
325 case '\b': fprintf(stderr, "\b"); break;
326 case '\n': fprintf(stderr, "\n"); break;
327 case '\r': fprintf(stderr, "\r"); break;
329 if (c >= 32 && c < 127)
330 fprintf(stderr, "%c", c);
332 fprintf(stderr, "\\x%02X", c);
335 fprintf(stderr, "\"");
338 /* assertEqualString() displays the values of the two strings. */
340 test_assert_equal_string(const char *file, int line,
341 const char *v1, const char *e1,
342 const char *v2, const char *e2,
345 count_assertion(file, line);
346 if (v1 == NULL || v2 == NULL) {
351 } else if (strcmp(v1, v2) == 0) {
356 if (!verbose && previous_failures(file, line, 1))
358 fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n",
360 fprintf(stderr, " %s = ", e1);
362 fprintf(stderr, " (length %d)\n", v1 == NULL ? 0 : (int)strlen(v1));
363 fprintf(stderr, " %s = ", e2);
365 fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : (int)strlen(v2));
366 report_failure(extra);
370 static void wcsdump(const wchar_t *w)
373 fprintf(stderr, "(null)");
376 fprintf(stderr, "\"");
377 while (*w != L'\0') {
378 unsigned int c = *w++;
379 if (c >= 32 && c < 127)
380 fprintf(stderr, "%c", c);
382 fprintf(stderr, "\\x%02X", c);
383 else if (c < 0x10000)
384 fprintf(stderr, "\\u%04X", c);
386 fprintf(stderr, "\\U%08X", c);
388 fprintf(stderr, "\"");
391 /* assertEqualWString() displays the values of the two strings. */
393 test_assert_equal_wstring(const char *file, int line,
394 const wchar_t *v1, const char *e1,
395 const wchar_t *v2, const char *e2,
398 count_assertion(file, line);
404 } else if (v2 == NULL) {
409 } else if (wcscmp(v1, v2) == 0) {
414 if (!verbose && previous_failures(file, line, 1))
416 fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n",
418 fprintf(stderr, " %s = ", e1);
420 fprintf(stderr, "\n");
421 fprintf(stderr, " %s = ", e2);
423 fprintf(stderr, "\n");
424 report_failure(extra);
429 * Pretty standard hexdump routine. As a bonus, if ref != NULL, then
430 * any bytes in p that differ from ref will be highlighted with '_'
431 * before and after the hex value.
434 hexdump(const char *p, const char *ref, size_t l, size_t offset)
439 for(i=0; i < l; i+=16) {
440 fprintf(stderr, "%04x", (unsigned)(i + offset));
442 for (j = 0; j < 16 && i + j < l; j++) {
443 if (ref != NULL && p[i + j] != ref[i + j])
445 fprintf(stderr, "%c%02x", sep, 0xff & (int)p[i+j]);
446 if (ref != NULL && p[i + j] == ref[i + j])
449 for (; j < 16; j++) {
450 fprintf(stderr, "%c ", sep);
453 fprintf(stderr, "%c", sep);
454 for (j=0; j < 16 && i + j < l; j++) {
456 if (c >= ' ' && c <= 126)
457 fprintf(stderr, "%c", c);
459 fprintf(stderr, ".");
461 fprintf(stderr, "\n");
465 /* assertEqualMem() displays the values of the two memory blocks. */
467 test_assert_equal_mem(const char *file, int line,
468 const void *_v1, const char *e1,
469 const void *_v2, const char *e2,
470 size_t l, const char *ld, void *extra)
472 const char *v1 = (const char *)_v1;
473 const char *v2 = (const char *)_v2;
476 count_assertion(file, line);
477 if (v1 == NULL || v2 == NULL) {
482 } else if (memcmp(v1, v2, l) == 0) {
487 if (!verbose && previous_failures(file, line, 1))
489 fprintf(stderr, "%s:%d: Assertion failed: memory not equal\n",
491 fprintf(stderr, " size %s = %d\n", ld, (int)l);
492 /* Dump 48 bytes (3 lines) so that the first difference is
493 * in the second line. */
495 while (l > 64 && memcmp(v1, v2, 32) == 0) {
496 /* The first two lines agree, so step forward one line. */
502 fprintf(stderr, " Dump of %s\n", e1);
503 hexdump(v1, v2, l < 64 ? l : 64, offset);
504 fprintf(stderr, " Dump of %s\n", e2);
505 hexdump(v2, v1, l < 64 ? l : 64, offset);
506 fprintf(stderr, "\n");
507 report_failure(extra);
512 test_assert_empty_file(const char *f1fmt, ...)
523 vsprintf(f1, f1fmt, ap);
526 if (stat(f1, &st) != 0) {
527 fprintf(stderr, "%s:%d: Could not stat: %s\n", test_filename, test_line, f1);
528 report_failure(NULL);
535 if (!verbose && previous_failures(test_filename, test_line, 1))
538 fprintf(stderr, "%s:%d: File not empty: %s\n", test_filename, test_line, f1);
539 fprintf(stderr, " File size: %d\n", (int)st.st_size);
540 fprintf(stderr, " Contents:\n");
541 fd = open(f1, O_RDONLY);
543 fprintf(stderr, " Unable to open %s\n", f1);
545 s = sizeof(buff) < st.st_size ? sizeof(buff) : st.st_size;
546 s = read(fd, buff, s);
547 hexdump(buff, NULL, s, 0);
549 report_failure(NULL);
553 /* assertEqualFile() asserts that two files have the same contents. */
554 /* TODO: hexdump the first bytes that actually differ. */
556 test_assert_equal_file(const char *f1, const char *f2pattern, ...)
565 va_start(ap, f2pattern);
566 vsprintf(f2, f2pattern, ap);
569 fd1 = open(f1, O_RDONLY);
570 fd2 = open(f2, O_RDONLY);
572 n1 = read(fd1, buff1, sizeof(buff1));
573 n2 = read(fd2, buff2, sizeof(buff2));
576 if (n1 == 0 && n2 == 0)
578 if (memcmp(buff1, buff2, n1) != 0)
582 if (!verbose && previous_failures(test_filename, test_line, 1))
584 fprintf(stderr, "%s:%d: Files are not identical\n",
585 test_filename, test_line);
586 fprintf(stderr, " file1=\"%s\"\n", f1);
587 fprintf(stderr, " file2=\"%s\"\n", f2);
588 report_failure(test_extra);
593 test_assert_file_exists(const char *fpattern, ...)
598 va_start(ap, fpattern);
599 vsprintf(f, fpattern, ap);
602 if (!access(f, F_OK))
604 if (!previous_failures(test_filename, test_line, 1)) {
605 fprintf(stderr, "%s:%d: File doesn't exist\n",
606 test_filename, test_line);
607 fprintf(stderr, " file=\"%s\"\n", f);
608 report_failure(test_extra);
614 test_assert_file_not_exists(const char *fpattern, ...)
619 va_start(ap, fpattern);
620 vsprintf(f, fpattern, ap);
625 if (!previous_failures(test_filename, test_line, 1)) {
626 fprintf(stderr, "%s:%d: File exists and shouldn't\n",
627 test_filename, test_line);
628 fprintf(stderr, " file=\"%s\"\n", f);
629 report_failure(test_extra);
634 /* assertFileContents() asserts the contents of a file. */
636 test_assert_file_contents(const void *buff, int s, const char *fpattern, ...)
644 va_start(ap, fpattern);
645 vsprintf(f, fpattern, ap);
648 fd = open(f, O_RDONLY);
649 contents = malloc(s * 2);
650 n = read(fd, contents, s * 2);
651 if (n == s && memcmp(buff, contents, s) == 0) {
656 if (!previous_failures(test_filename, test_line, 1)) {
657 fprintf(stderr, "%s:%d: File contents don't match\n",
658 test_filename, test_line);
659 fprintf(stderr, " file=\"%s\"\n", f);
661 hexdump(contents, buff, n, 0);
663 fprintf(stderr, " File empty, contents should be:\n");
664 hexdump(buff, NULL, s, 0);
666 report_failure(test_extra);
673 * Call standard system() call, but build up the command line using
674 * sprintf() conventions.
677 systemf(const char *fmt, ...)
684 vsprintf(buff, fmt, ap);
691 * Slurp a file into memory for ease of comparison and testing.
692 * Returns size of file in 'sizep' if non-NULL, null-terminates
693 * data in memory for ease of use.
696 slurpfile(size_t * sizep, const char *fmt, ...)
707 vsprintf(filename, fmt, ap);
710 fd = open(filename, O_RDONLY);
712 /* Note: No error; non-existent file is okay here. */
717 fprintf(stderr, "Can't stat file %s\n", filename);
721 p = malloc(st.st_size + 1);
723 fprintf(stderr, "Can't allocate %ld bytes of memory to read file %s\n", (long int)st.st_size, filename);
727 bytes_read = read(fd, p, st.st_size);
728 if (bytes_read < st.st_size) {
729 fprintf(stderr, "Can't read file %s\n", filename);
734 p[st.st_size] = '\0';
736 *sizep = (size_t)st.st_size;
742 * "list.h" is automatically generated; it just has a lot of lines like:
743 * DEFINE_TEST(function_name)
744 * It's used above to declare all of the test functions.
745 * We reuse it here to define a list of all tests (functions and names).
748 #define DEFINE_TEST(n) { n, #n },
749 struct { void (*func)(void); const char *name; } tests[] = {
754 * This is well-intentioned, but sometimes the standard libraries
755 * leave open file descriptors and expect to be able to come back to
756 * them (e.g., for username lookups or logging). Closing these
757 * descriptors out from under those libraries creates havoc.
759 * Maybe there's some reasonably portable way to tell if a descriptor
760 * is open without using close()?
764 close_descriptors(int warn)
769 for (i = 3; i < 100; ++i) {
773 if (warn && left_open > 0) {
774 fprintf(stderr, " ** %d descriptors unclosed\n", left_open);
775 failures += left_open;
776 report_failure(NULL);
782 * Each test is run in a private work dir. Those work dirs
783 * do have consistent and predictable names, in case a group
784 * of tests need to collaborate. However, there is no provision
785 * for requiring that tests run in a certain order.
787 static int test_run(int i, const char *tmpdir)
789 int failures_before = failures;
792 printf("%d: %s\n", i, tests[i].name);
797 * Always explicitly chdir() in case the last test moved us to
802 "ERROR: Couldn't chdir to temp dir %s\n",
806 /* Create a temp directory for this specific test. */
807 if (mkdir(tests[i].name, 0755)) {
809 "ERROR: Couldn't create temp dir ``%s''\n",
813 /* Chdir() to that work directory. */
814 if (chdir(tests[i].name)) {
816 "ERROR: Couldn't chdir to temp dir ``%s''\n",
820 /* Explicitly reset the locale before each test. */
821 setlocale(LC_ALL, "C");
822 /* Make sure there are no stray descriptors going into the test. */
823 /* TODO: Find a better way to identify file descriptor leaks. */
824 //close_descriptors(0);
825 /* Run the actual test. */
827 /* Close stray descriptors, record as errors against this test. */
828 //close_descriptors(1);
829 /* Summarize the results of this test. */
831 /* If there were no failures, we can remove the work dir. */
832 if (failures == failures_before) {
833 if (!keep_temp_files && chdir(tmpdir) == 0) {
834 #if !defined(_WIN32) || defined(__CYGWIN__)
835 systemf("rm -rf %s", tests[i].name);
837 systemf("rmdir /S /Q %s", tests[i].name);
841 /* Return appropriate status. */
842 return (failures == failures_before ? 0 : 1);
845 static void usage(const char *program)
847 static const int limit = sizeof(tests) / sizeof(tests[0]);
850 printf("Usage: %s [options] <test> <test> ...\n", program);
851 printf("Default is to run all tests.\n");
852 printf("Otherwise, specify the numbers of the tests you wish to run.\n");
853 printf("Options:\n");
854 printf(" -d Dump core after any failure, for debugging.\n");
855 printf(" -k Keep all temp files.\n");
856 printf(" Default: temp files for successful tests deleted.\n");
858 printf(" -p <path> Path to executable to be tested.\n");
859 printf(" Default: path taken from " ENVBASE " environment variable.\n");
861 printf(" -q Quiet.\n");
862 printf(" -r <dir> Path to dir containing reference files.\n");
863 printf(" Default: Current directory.\n");
864 printf(" -v Verbose.\n");
865 printf("Available tests:\n");
866 for (i = 0; i < limit; i++)
867 printf(" %d: %s\n", i, tests[i].name);
871 #define UUDECODE(c) (((c) - 0x20) & 0x3f)
874 extract_reference_file(const char *name)
879 sprintf(buff, "%s/%s.uu", refdir, name);
880 in = fopen(buff, "r");
881 failure("Couldn't open reference file %s", buff);
885 /* Read up to and including the 'begin' line. */
887 if (fgets(buff, sizeof(buff), in) == NULL) {
888 /* TODO: This is a failure. */
891 if (memcmp(buff, "begin ", 6) == 0)
894 /* Now, decode the rest and write it. */
895 /* Not a lot of error checking here; the input better be right. */
896 out = fopen(name, "w");
897 while (fgets(buff, sizeof(buff), in) != NULL) {
901 if (memcmp(buff, "end", 3) == 0)
904 bytes = UUDECODE(*p++);
907 /* Write out 1-3 bytes from that. */
909 n = UUDECODE(*p++) << 18;
910 n |= UUDECODE(*p++) << 12;
915 n |= UUDECODE(*p++) << 6;
916 fputc((n >> 8) & 0xFF, out);
921 fputc(n & 0xFF, out);
931 /* Since gzip is by far the most popular external compression program
932 * available, we try to use it in the read_program and write_program
933 * tests. But if it's not available, then we can't use it. This
934 * function just tries to run gzip/gunzip to see if they're available.
935 * If not, some of the external compression program tests will be
938 external_gzip_program(int un)
940 static int tested = 0;
941 static const char *compress_prog = NULL;
942 static const char *decompress_prog = NULL;
943 /* Args vary depending on the command interpreter we're using. */
944 #if defined(_WIN32) && !defined(__CYGWIN__)
945 static const char *args = "-V >NUL 2>NUL"; /* Win32 cmd.exe */
947 static const char *args = "-V >/dev/null 2>/dev/null"; /* POSIX 'sh' */
951 if (systemf("gunzip %s", args) == 0)
952 decompress_prog = "gunzip";
953 if (systemf("gzip %s", args) == 0)
954 compress_prog = "gzip";
957 return (un ? decompress_prog : compress_prog);
963 char tried[512] = { '\0' };
967 /* Get the current dir. */
968 pwd = getcwd(NULL, 0);
969 while (pwd[strlen(pwd) - 1] == '\n')
970 pwd[strlen(pwd) - 1] = '\0';
971 printf("PWD: %s\n", pwd);
973 /* Look for a known file. */
974 snprintf(buff, sizeof(buff), "%s", pwd);
975 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
976 if (p != NULL) goto success;
977 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
978 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
980 snprintf(buff, sizeof(buff), "%s/test", pwd);
981 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
982 if (p != NULL) goto success;
983 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
984 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
986 snprintf(buff, sizeof(buff), "%s/%s/test", pwd, LIBRARY);
987 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
988 if (p != NULL) goto success;
989 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
990 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
992 if (memcmp(pwd, "/usr/obj", 8) == 0) {
993 snprintf(buff, sizeof(buff), "%s", pwd + 8);
994 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
995 if (p != NULL) goto success;
996 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
997 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
999 snprintf(buff, sizeof(buff), "%s/test", pwd + 8);
1000 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
1001 if (p != NULL) goto success;
1002 strncat(tried, buff, sizeof(tried) - strlen(tried) - 1);
1003 strncat(tried, "\n", sizeof(tried) - strlen(tried) - 1);
1006 #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
1009 printf("Unable to locate known reference file %s\n", KNOWNREF);
1010 printf(" Checked following directories:\n%s\n", tried);
1016 return strdup(buff);
1019 int main(int argc, char **argv)
1021 static const int limit = sizeof(tests) / sizeof(tests[0]);
1022 int i, tests_run = 0, tests_failed = 0, option;
1024 char *refdir_alloc = NULL;
1025 const char *progname = LIBRARY "_test";
1026 const char *tmp, *option_arg, *p;
1028 char tmpdir_timestamp[256];
1030 (void)argc; /* UNUSED */
1032 #if defined(_WIN32) && !defined(__CYGWIN__)
1033 /* To stop to run the default invalid parameter handler. */
1034 _set_invalid_parameter_handler(invalid_parameter_handler);
1035 /* for open() to a binary mode. */
1036 _set_fmode(_O_BINARY);
1037 /* Disable annoying assertion message box. */
1038 _CrtSetReportMode(_CRT_ASSERT, 0);
1042 /* Get the target program from environment, if available. */
1043 testprog = getenv(ENVBASE);
1046 if (getenv("TMPDIR") != NULL)
1047 tmp = getenv("TMPDIR");
1048 else if (getenv("TMP") != NULL)
1049 tmp = getenv("TMP");
1050 else if (getenv("TEMP") != NULL)
1051 tmp = getenv("TEMP");
1052 else if (getenv("TEMPDIR") != NULL)
1053 tmp = getenv("TEMPDIR");
1057 /* Allow -d to be controlled through the environment. */
1058 if (getenv(ENVBASE "_DEBUG") != NULL)
1059 dump_on_failure = 1;
1061 /* Get the directory holding test files from environment. */
1062 refdir = getenv(ENVBASE "_TEST_FILES");
1065 * Parse options, without using getopt(), which isn't available
1068 ++argv; /* Skip program name */
1069 while (*argv != NULL) {
1074 while (*p != '\0') {
1077 /* If 'opt' takes an argument, parse that. */
1078 if (option == 'p' || option == 'r') {
1081 else if (*argv == NULL) {
1083 "Option -%c requires argument.\n",
1087 option_arg = *argv++;
1088 p = ""; /* End of this option word. */
1091 /* Now, handle the option. */
1094 dump_on_failure = 1;
1097 keep_temp_files = 1;
1101 testprog = option_arg;
1110 refdir = option_arg;
1122 * Sanity-check that our options make sense.
1125 if (testprog == NULL)
1130 * Create a temp directory for the following tests.
1131 * Include the time the tests started as part of the name,
1132 * to make it easier to track the results of multiple tests.
1135 for (i = 0; i < 1000; i++) {
1136 strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp),
1137 "%Y-%m-%dT%H.%M.%S",
1139 sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname,
1140 tmpdir_timestamp, i);
1141 if (mkdir(tmpdir,0755) == 0)
1143 if (errno == EEXIST)
1145 fprintf(stderr, "ERROR: Unable to create temp directory %s\n",
1151 * If the user didn't specify a directory for locating
1152 * reference files, try to find the reference files in
1153 * the "usual places."
1156 refdir = refdir_alloc = get_refdir();
1159 * Banner with basic information.
1162 printf("Running tests in: %s\n", tmpdir);
1163 printf("Reference files will be read from: %s\n", refdir);
1165 printf("Running tests on: %s\n", testprog);
1167 printf("Exercising: ");
1169 printf("%s\n", EXTRA_VERSION);
1173 * Run some or all of the individual tests.
1175 if (*argv == NULL) {
1176 /* Default: Run all tests. */
1177 for (i = 0; i < limit; i++) {
1178 if (test_run(i, tmpdir))
1183 while (*(argv) != NULL) {
1184 if (**argv >= '0' && **argv <= '9') {
1186 if (i < 0 || i >= limit) {
1187 printf("*** INVALID Test %s\n", *argv);
1190 /* usage() never returns */
1193 for (i = 0; i < limit; ++i) {
1194 if (strcmp(*argv, tests[i].name) == 0)
1198 printf("*** INVALID Test ``%s''\n",
1202 /* usage() never returns */
1205 if (test_run(i, tmpdir))
1213 * Report summary statistics.
1217 printf("%d of %d tests reported failures\n",
1218 tests_failed, tests_run);
1219 printf(" Total of %d assertions checked.\n", assertions);
1220 printf(" Total of %d assertions failed.\n", failures);
1221 printf(" Total of %d reported skips.\n", skips);
1226 /* If the final tmpdir is empty, we can remove it. */
1227 /* This should be the usual case when all tests succeed. */
1230 return (tests_failed);