diff options
author | Martin Matuska <martin@matuska.org> | 2017-02-21 16:46:45 +0100 |
---|---|---|
committer | Martin Matuska <martin@matuska.org> | 2017-02-21 21:10:49 +0100 |
commit | 52d5a14c210e41adf3b94f289ed5a0a45aa27c44 (patch) | |
tree | 45d7e99bc2813a1b1039d832f8bf9c75cdee6af5 | |
parent | 042dc9445a45ff789a2fac9dd6976ec2df8b6f98 (diff) | |
download | libarchive-52d5a14c210e41adf3b94f289ed5a0a45aa27c44.tar.gz |
test suite: use a single main test file for all tests
-rw-r--r-- | Makefile.am | 25 | ||||
-rw-r--r-- | cat/test/CMakeLists.txt | 4 | ||||
-rw-r--r-- | cat/test/main.c | 3072 | ||||
-rw-r--r-- | cat/test/test.h | 338 | ||||
-rw-r--r-- | cat/test/test_version.c | 4 | ||||
-rw-r--r-- | cpio/test/CMakeLists.txt | 4 | ||||
-rw-r--r-- | cpio/test/main.c | 3073 | ||||
-rw-r--r-- | cpio/test/test.h | 340 | ||||
-rw-r--r-- | cpio/test/test_option_version.c | 5 | ||||
-rw-r--r-- | libarchive/test/CMakeLists.txt | 4 | ||||
-rw-r--r-- | libarchive/test/test.h | 390 | ||||
-rw-r--r-- | tar/test/CMakeLists.txt | 4 | ||||
-rw-r--r-- | tar/test/main.c | 3072 | ||||
-rw-r--r-- | tar/test/test.h | 340 | ||||
-rw-r--r-- | tar/test/test_version.c | 5 | ||||
-rw-r--r-- | test_utils/lib/version.c | 132 | ||||
-rw-r--r-- | test_utils/lib/version.h | 31 | ||||
-rw-r--r-- | test_utils/test_common.h | 428 | ||||
-rw-r--r-- | test_utils/test_main.c (renamed from libarchive/test/main.c) | 129 |
19 files changed, 614 insertions, 10786 deletions
diff --git a/Makefile.am b/Makefile.am index 56a19abf..a699dc57 100644 --- a/Makefile.am +++ b/Makefile.am @@ -311,8 +311,8 @@ pkgconfig_DATA = build/pkgconfig/libarchive.pc test_utils_SOURCES= \ test_utils/test_utils.c \ test_utils/test_utils.h \ - test_utils/lib/version.h \ - test_utils/lib/version.c + test_utils/test_main.c \ + test_utils/test_common.h # # @@ -322,7 +322,6 @@ test_utils_SOURCES= \ libarchive_test_SOURCES= \ $(libarchive_la_SOURCES) \ $(test_utils_SOURCES) \ - libarchive/test/main.c \ libarchive/test/read_open_memory.c \ libarchive/test/test.h \ libarchive/test/test_acl_nfs4.c \ @@ -588,7 +587,13 @@ libarchive_test_SOURCES= \ libarchive/test/test_write_read_format_zip.c \ libarchive/test/test_zip_filename_encoding.c -libarchive_test_CPPFLAGS= -I$(top_srcdir)/libarchive -I$(top_srcdir)/test_utils -I$(top_builddir)/libarchive/test -DLIBARCHIVE_STATIC $(PLATFORMCPPFLAGS) +libarchive_test_CPPFLAGS= \ + -I$(top_srcdir)/libarchive \ + -I$(top_srcdir)/libarchive/test \ + -I$(top_srcdir)/test_utils \ + -I$(top_builddir)/libarchive/test \ + -DLIBARCHIVE_STATIC $(PLATFORMCPPFLAGS) + libarchive_test_LDADD= $(LTLIBICONV) # The "list.h" file just lists all of the tests defined in all of the sources. @@ -920,7 +925,6 @@ endif bsdtar_test_SOURCES= \ $(test_utils_SOURCES) \ - tar/test/main.c \ tar/test/test.h \ tar/test/test_0.c \ tar/test/test_basic.c \ @@ -983,7 +987,8 @@ bsdtar_test_SOURCES= \ bsdtar_test_CPPFLAGS=\ -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \ -I$(top_srcdir)/test_utils \ - -I$(top_srcdir)/tar -I$(top_builddir)/tar/test \ + -I$(top_srcdir)/tar -I$(top_srcdir)/tar/test \ + -I$(top_builddir)/tar/test \ $(PLATFORMCPPFLAGS) tar/test/list.h: Makefile @@ -1078,7 +1083,6 @@ endif bsdcpio_test_SOURCES= \ $(test_utils_SOURCES) \ cpio/cmdline.c \ - cpio/test/main.c \ cpio/test/test.h \ cpio/test/test_0.c \ cpio/test/test_basic.c \ @@ -1130,7 +1134,8 @@ bsdcpio_test_SOURCES= \ bsdcpio_test_CPPFLAGS= \ -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \ -I$(top_srcdir)/test_utils \ - -I$(top_srcdir)/cpio -I$(top_builddir)/cpio/test \ + -I$(top_srcdir)/cpio -I$(top_srcdir)/cpio/test \ + -I$(top_builddir)/cpio/test \ $(PLATFORMCPPFLAGS) bsdcpio_test_LDADD=libarchive_fe.la @@ -1225,7 +1230,6 @@ endif bsdcat_test_SOURCES= \ $(test_utils_SOURCES) \ - cat/test/main.c \ cat/test/test.h \ cat/test/test_0.c \ cat/test/test_empty_gz.c \ @@ -1246,7 +1250,8 @@ bsdcat_test_SOURCES= \ bsdcat_test_CPPFLAGS= \ -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \ -I$(top_srcdir)/test_utils \ - -I$(top_srcdir)/cat -I$(top_builddir)/cat/test \ + -I$(top_srcdir)/cat -I$(top_srcdir)/cat/test \ + -I$(top_builddir)/cat/test \ $(PLATFORMCPPFLAGS) bsdcat_test_LDADD=libarchive_fe.la diff --git a/cat/test/CMakeLists.txt b/cat/test/CMakeLists.txt index 9dbf4b79..7f1ce5e7 100644 --- a/cat/test/CMakeLists.txt +++ b/cat/test/CMakeLists.txt @@ -6,8 +6,7 @@ IF(ENABLE_CAT AND ENABLE_TEST) SET(bsdcat_test_SOURCES ../../test_utils/test_utils.c - ../../test_utils/lib/version.c - main.c + ../../test_utils/test_main.c test.h test_0.c test_empty_gz.c @@ -55,6 +54,7 @@ IF(ENABLE_CAT AND ENABLE_TEST) INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cat/test) # Experimental new test handling ADD_CUSTOM_TARGET(run_bsdcat_test diff --git a/cat/test/main.c b/cat/test/main.c deleted file mode 100644 index cdfdd9bd..00000000 --- a/cat/test/main.c +++ /dev/null @@ -1,3072 +0,0 @@ -/* - * Copyright (c) 2003-2009 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "test.h" -#include "test_utils.h" -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#include <errno.h> -#ifdef HAVE_ICONV_H -#include <iconv.h> -#endif -/* - * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. - * As the include guards don't agree, the order of include is important. - */ -#ifdef HAVE_LINUX_EXT2_FS_H -#include <linux/ext2_fs.h> /* for Linux file flags */ -#endif -#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) -#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ -#endif -#include <limits.h> -#include <locale.h> -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#include <stdarg.h> -#include <time.h> - -/* - * This same file is used pretty much verbatim for all test harnesses. - * - * The next few lines are the only differences. - * TODO: Move this into a separate configuration header, have all test - * suites share one copy of this file. - */ -#define KNOWNREF "test_expand.Z.uu" -#define ENVBASE "BSDCAT" /* Prefix for environment variables. */ -#define PROGRAM "bsdcat" /* Name of program being tested. */ -#define PROGRAM_ALIAS "cat" /* Generic alias for program */ -#undef LIBRARY /* Not testing a library. */ -#undef EXTRA_DUMP /* How to dump extra data */ -#undef EXTRA_ERRNO /* How to dump errno */ -/* How to generate extra version info. */ -#define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") - -/* - * - * Windows support routines - * - * Note: Configuration is a tricky issue. Using HAVE_* feature macros - * in the test harness is dangerous because they cover up - * configuration errors. The classic example of this is omitting a - * configure check. If libarchive and libarchive_test both look for - * the same feature macro, such errors are hard to detect. Platform - * macros (e.g., _WIN32 or __GNUC__) are a little better, but can - * easily lead to very messy code. It's best to limit yourself - * to only the most generic programming techniques in the test harness - * and thus avoid conditionals altogether. Where that's not possible, - * try to minimize conditionals by grouping platform-specific tests in - * one place (e.g., test_acl_freebsd) or by adding new assert() - * functions (e.g., assertMakeHardlink()) to cover up platform - * differences. Platform-specific coding in libarchive_test is often - * a symptom that some capability is missing from libarchive itself. - */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#include <io.h> -#include <direct.h> -#include <windows.h> -#ifndef F_OK -#define F_OK (0) -#endif -#ifndef S_ISDIR -#define S_ISDIR(m) ((m) & _S_IFDIR) -#endif -#ifndef S_ISREG -#define S_ISREG(m) ((m) & _S_IFREG) -#endif -#if !defined(__BORLANDC__) -#define access _access -#undef chdir -#define chdir _chdir -#endif -#ifndef fileno -#define fileno _fileno -#endif -/*#define fstat _fstat64*/ -#if !defined(__BORLANDC__) -#define getcwd _getcwd -#endif -#define lstat stat -/*#define lstat _stat64*/ -/*#define stat _stat64*/ -#define rmdir _rmdir -#if !defined(__BORLANDC__) -#define strdup _strdup -#define umask _umask -#endif -#define int64_t __int64 -#endif - -#if defined(HAVE__CrtSetReportMode) -# include <crtdbg.h> -#endif - -mode_t umasked(mode_t expected_mode) -{ - mode_t mode = umask(0); - umask(mode); - return expected_mode & ~mode; -} - -/* Path to working directory for current test */ -const char *testworkdir; -#ifdef PROGRAM -/* Pathname of exe to be tested. */ -const char *testprogfile; -/* Name of exe to use in printf-formatted command strings. */ -/* On Windows, this includes leading/trailing quotes. */ -const char *testprog; -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) -static void *GetFunctionKernel32(const char *); -static int my_CreateSymbolicLinkA(const char *, const char *, int); -static int my_CreateHardLinkA(const char *, const char *); -static int my_GetFileInformationByName(const char *, - BY_HANDLE_FILE_INFORMATION *); - -static void * -GetFunctionKernel32(const char *name) -{ - static HINSTANCE lib; - static int set; - if (!set) { - set = 1; - lib = LoadLibrary("kernel32.dll"); - } - if (lib == NULL) { - fprintf(stderr, "Can't load kernel32.dll?!\n"); - exit(1); - } - return (void *)GetProcAddress(lib, name); -} - -static int -my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags) -{ - static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD); - static int set; - if (!set) { - set = 1; - f = GetFunctionKernel32("CreateSymbolicLinkA"); - } - return f == NULL ? 0 : (*f)(linkname, target, flags); -} - -static int -my_CreateHardLinkA(const char *linkname, const char *target) -{ - static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); - static int set; - if (!set) { - set = 1; - f = GetFunctionKernel32("CreateHardLinkA"); - } - return f == NULL ? 0 : (*f)(linkname, target, NULL); -} - -static int -my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) -{ - HANDLE h; - int r; - - memset(bhfi, 0, sizeof(*bhfi)); - h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) - return (0); - r = GetFileInformationByHandle(h, bhfi); - CloseHandle(h); - return (r); -} -#endif - -#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__) -static void -invalid_parameter_handler(const wchar_t * expression, - const wchar_t * function, const wchar_t * file, - unsigned int line, uintptr_t pReserved) -{ - /* nop */ -} -#endif - -/* - * - * OPTIONS FLAGS - * - */ - -/* Enable core dump on failure. */ -static int dump_on_failure = 0; -/* Default is to remove temp dirs and log data for successful tests. */ -static int keep_temp_files = 0; -/* Default is to run the specified tests once and report errors. */ -static int until_failure = 0; -/* Default is to just report pass/fail for each test. */ -static int verbosity = 0; -#define VERBOSITY_SUMMARY_ONLY -1 /* -q */ -#define VERBOSITY_PASSFAIL 0 /* Default */ -#define VERBOSITY_LIGHT_REPORT 1 /* -v */ -#define VERBOSITY_FULL 2 /* -vv */ -/* A few places generate even more output for verbosity > VERBOSITY_FULL, - * mostly for debugging the test harness itself. */ -/* Cumulative count of assertion failures. */ -static int failures = 0; -/* Cumulative count of reported skips. */ -static int skips = 0; -/* Cumulative count of assertions checked. */ -static int assertions = 0; - -/* Directory where uuencoded reference files can be found. */ -static const char *refdir; - -/* - * Report log information selectively to console and/or disk log. - */ -static int log_console = 0; -static FILE *logfile; -static void -vlogprintf(const char *fmt, va_list ap) -{ -#ifdef va_copy - va_list lfap; - va_copy(lfap, ap); -#endif - if (log_console) - vfprintf(stdout, fmt, ap); - if (logfile != NULL) -#ifdef va_copy - vfprintf(logfile, fmt, lfap); - va_end(lfap); -#else - vfprintf(logfile, fmt, ap); -#endif -} - -static void -logprintf(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vlogprintf(fmt, ap); - va_end(ap); -} - -/* Set up a message to display only if next assertion fails. */ -static char msgbuff[4096]; -static const char *msg, *nextmsg; -void -failure(const char *fmt, ...) -{ - va_list ap; - if (fmt == NULL) { - nextmsg = NULL; - } else { - va_start(ap, fmt); - vsprintf(msgbuff, fmt, ap); - va_end(ap); - nextmsg = msgbuff; - } -} - -/* - * Copy arguments into file-local variables. - * This was added to permit vararg assert() functions without needing - * variadic wrapper macros. Turns out that the vararg capability is almost - * never used, so almost all of the vararg assertions can be simplified - * by removing the vararg capability and reworking the wrapper macro to - * pass __FILE__, __LINE__ directly into the function instead of using - * this hook. I suspect this machinery is used so rarely that we - * would be better off just removing it entirely. That would simplify - * the code here noticeably. - */ -static const char *skipping_filename; -static int skipping_line; -void skipping_setup(const char *filename, int line) -{ - skipping_filename = filename; - skipping_line = line; -} - -/* Called at the beginning of each assert() function. */ -static void -assertion_count(const char *file, int line) -{ - (void)file; /* UNUSED */ - (void)line; /* UNUSED */ - ++assertions; - /* Proper handling of "failure()" message. */ - msg = nextmsg; - nextmsg = NULL; - /* Uncomment to print file:line after every assertion. - * Verbose, but occasionally useful in tracking down crashes. */ - /* printf("Checked %s:%d\n", file, line); */ -} - -/* - * For each test source file, we remember how many times each - * assertion was reported. Cleared before each new test, - * used by test_summarize(). - */ -static struct line { - int count; - int skip; -} failed_lines[10000]; -const char *failed_filename; - -/* Count this failure, setup up log destination and handle initial report. */ -static void -failure_start(const char *filename, int line, const char *fmt, ...) -{ - va_list ap; - - /* Record another failure for this line. */ - ++failures; - failed_filename = filename; - failed_lines[line].count++; - - /* Determine whether to log header to console. */ - switch (verbosity) { - case VERBOSITY_LIGHT_REPORT: - log_console = (failed_lines[line].count < 2); - break; - default: - log_console = (verbosity >= VERBOSITY_FULL); - } - - /* Log file:line header for this failure */ - va_start(ap, fmt); -#if _MSC_VER - logprintf("%s(%d): ", filename, line); -#else - logprintf("%s:%d: ", filename, line); -#endif - vlogprintf(fmt, ap); - va_end(ap); - logprintf("\n"); - - if (msg != NULL && msg[0] != '\0') { - logprintf(" Description: %s\n", msg); - msg = NULL; - } - - /* Determine whether to log details to console. */ - if (verbosity == VERBOSITY_LIGHT_REPORT) - log_console = 0; -} - -/* Complete reporting of failed tests. */ -/* - * The 'extra' hook here is used by libarchive to include libarchive - * error messages with assertion failures. It could also be used - * to add strerror() output, for example. Just define the EXTRA_DUMP() - * macro appropriately. - */ -static void -failure_finish(void *extra) -{ - (void)extra; /* UNUSED (maybe) */ -#ifdef EXTRA_DUMP - if (extra != NULL) { - logprintf(" errno: %d\n", EXTRA_ERRNO(extra)); - logprintf(" detail: %s\n", EXTRA_DUMP(extra)); - } -#endif - - if (dump_on_failure) { - fprintf(stderr, - " *** forcing core dump so failure can be debugged ***\n"); - abort(); - } -} - -/* Inform user that we're skipping some checks. */ -void -test_skipping(const char *fmt, ...) -{ - char buff[1024]; - va_list ap; - - va_start(ap, fmt); - vsprintf(buff, fmt, ap); - va_end(ap); - /* Use failure() message if set. */ - msg = nextmsg; - nextmsg = NULL; - /* failure_start() isn't quite right, but is awfully convenient. */ - failure_start(skipping_filename, skipping_line, "SKIPPING: %s", buff); - --failures; /* Undo failures++ in failure_start() */ - /* Don't failure_finish() here. */ - /* Mark as skip, so doesn't count as failed test. */ - failed_lines[skipping_line].skip = 1; - ++skips; -} - -/* - * - * ASSERTIONS - * - */ - -/* Generic assert() just displays the failed condition. */ -int -assertion_assert(const char *file, int line, int value, - const char *condition, void *extra) -{ - assertion_count(file, line); - if (!value) { - failure_start(file, line, "Assertion failed: %s", condition); - failure_finish(extra); - } - return (value); -} - -/* chdir() and report any errors */ -int -assertion_chdir(const char *file, int line, const char *pathname) -{ - assertion_count(file, line); - if (chdir(pathname) == 0) - return (1); - failure_start(file, line, "chdir(\"%s\")", pathname); - failure_finish(NULL); - return (0); - -} - -/* Verify two integers are equal. */ -int -assertion_equal_int(const char *file, int line, - long long v1, const char *e1, long long v2, const char *e2, void *extra) -{ - assertion_count(file, line); - if (v1 == v2) - return (1); - failure_start(file, line, "%s != %s", e1, e2); - logprintf(" %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1); - logprintf(" %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2); - failure_finish(extra); - return (0); -} - -/* - * Utility to convert a single UTF-8 sequence. - */ -static int -_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) -{ - static const char utf8_count[256] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */ - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */ - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ - }; - int ch; - int cnt; - uint32_t wc; - - *pwc = 0; - - /* Sanity check. */ - if (n == 0) - return (0); - /* - * Decode 1-4 bytes depending on the value of the first byte. - */ - ch = (unsigned char)*s; - if (ch == 0) - return (0); /* Standard: return 0 for end-of-string. */ - cnt = utf8_count[ch]; - - /* Invalid sequence or there are not plenty bytes. */ - if (n < (size_t)cnt) - return (-1); - - /* Make a Unicode code point from a single UTF-8 sequence. */ - switch (cnt) { - case 1: /* 1 byte sequence. */ - *pwc = ch & 0x7f; - return (cnt); - case 2: /* 2 bytes sequence. */ - if ((s[1] & 0xc0) != 0x80) return (-1); - *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f); - return (cnt); - case 3: /* 3 bytes sequence. */ - if ((s[1] & 0xc0) != 0x80) return (-1); - if ((s[2] & 0xc0) != 0x80) return (-1); - wc = ((ch & 0x0f) << 12) - | ((s[1] & 0x3f) << 6) - | (s[2] & 0x3f); - if (wc < 0x800) - return (-1);/* Overlong sequence. */ - break; - case 4: /* 4 bytes sequence. */ - if (n < 4) - return (-1); - if ((s[1] & 0xc0) != 0x80) return (-1); - if ((s[2] & 0xc0) != 0x80) return (-1); - if ((s[3] & 0xc0) != 0x80) return (-1); - wc = ((ch & 0x07) << 18) - | ((s[1] & 0x3f) << 12) - | ((s[2] & 0x3f) << 6) - | (s[3] & 0x3f); - if (wc < 0x10000) - return (-1);/* Overlong sequence. */ - break; - default: - return (-1); - } - - /* The code point larger than 0x10FFFF is not legal - * Unicode values. */ - if (wc > 0x10FFFF) - return (-1); - /* Correctly gets a Unicode, returns used bytes. */ - *pwc = wc; - return (cnt); -} - -static void strdump(const char *e, const char *p, int ewidth, int utf8) -{ - const char *q = p; - - logprintf(" %*s = ", ewidth, e); - if (p == NULL) { - logprintf("NULL\n"); - return; - } - logprintf("\""); - while (*p != '\0') { - unsigned int c = 0xff & *p++; - switch (c) { - case '\a': logprintf("\\a"); break; - case '\b': logprintf("\\b"); break; - case '\n': logprintf("\\n"); break; - case '\r': logprintf("\\r"); break; - default: - if (c >= 32 && c < 127) - logprintf("%c", c); - else - logprintf("\\x%02X", c); - } - } - logprintf("\""); - logprintf(" (length %d)", q == NULL ? -1 : (int)strlen(q)); - - /* - * If the current string is UTF-8, dump its code points. - */ - if (utf8) { - size_t len; - uint32_t uc; - int n; - int cnt = 0; - - p = q; - len = strlen(p); - logprintf(" ["); - while ((n = _utf8_to_unicode(&uc, p, len)) > 0) { - if (p != q) - logprintf(" "); - logprintf("%04X", uc); - p += n; - len -= n; - cnt++; - } - logprintf("]"); - logprintf(" (count %d", cnt); - if (n < 0) { - logprintf(",unknown %d bytes", len); - } - logprintf(")"); - - } - logprintf("\n"); -} - -/* Verify two strings are equal, dump them if not. */ -int -assertion_equal_string(const char *file, int line, - const char *v1, const char *e1, - const char *v2, const char *e2, - void *extra, int utf8) -{ - int l1, l2; - - assertion_count(file, line); - if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0)) - return (1); - failure_start(file, line, "%s != %s", e1, e2); - l1 = (int)strlen(e1); - l2 = (int)strlen(e2); - if (l1 < l2) - l1 = l2; - strdump(e1, v1, l1, utf8); - strdump(e2, v2, l1, utf8); - failure_finish(extra); - return (0); -} - -static void -wcsdump(const char *e, const wchar_t *w) -{ - logprintf(" %s = ", e); - if (w == NULL) { - logprintf("(null)"); - return; - } - logprintf("\""); - while (*w != L'\0') { - unsigned int c = *w++; - if (c >= 32 && c < 127) - logprintf("%c", c); - else if (c < 256) - logprintf("\\x%02X", c); - else if (c < 0x10000) - logprintf("\\u%04X", c); - else - logprintf("\\U%08X", c); - } - logprintf("\"\n"); -} - -#ifndef HAVE_WCSCMP -static int -wcscmp(const wchar_t *s1, const wchar_t *s2) -{ - - while (*s1 == *s2++) { - if (*s1++ == L'\0') - return 0; - } - if (*s1 > *--s2) - return 1; - else - return -1; -} -#endif - -/* Verify that two wide strings are equal, dump them if not. */ -int -assertion_equal_wstring(const char *file, int line, - const wchar_t *v1, const char *e1, - const wchar_t *v2, const char *e2, - void *extra) -{ - assertion_count(file, line); - if (v1 == v2) - return (1); - if (v1 != NULL && v2 != NULL && wcscmp(v1, v2) == 0) - return (1); - failure_start(file, line, "%s != %s", e1, e2); - wcsdump(e1, v1); - wcsdump(e2, v2); - failure_finish(extra); - return (0); -} - -/* - * Pretty standard hexdump routine. As a bonus, if ref != NULL, then - * any bytes in p that differ from ref will be highlighted with '_' - * before and after the hex value. - */ -static void -hexdump(const char *p, const char *ref, size_t l, size_t offset) -{ - size_t i, j; - char sep; - - if (p == NULL) { - logprintf("(null)\n"); - return; - } - for(i=0; i < l; i+=16) { - logprintf("%04x", (unsigned)(i + offset)); - sep = ' '; - for (j = 0; j < 16 && i + j < l; j++) { - if (ref != NULL && p[i + j] != ref[i + j]) - sep = '_'; - logprintf("%c%02x", sep, 0xff & (int)p[i+j]); - if (ref != NULL && p[i + j] == ref[i + j]) - sep = ' '; - } - for (; j < 16; j++) { - logprintf("%c ", sep); - sep = ' '; - } - logprintf("%c", sep); - for (j=0; j < 16 && i + j < l; j++) { - int c = p[i + j]; - if (c >= ' ' && c <= 126) - logprintf("%c", c); - else - logprintf("."); - } - logprintf("\n"); - } -} - -/* Verify that two blocks of memory are the same, display the first - * block of differences if they're not. */ -int -assertion_equal_mem(const char *file, int line, - const void *_v1, const char *e1, - const void *_v2, const char *e2, - size_t l, const char *ld, void *extra) -{ - const char *v1 = (const char *)_v1; - const char *v2 = (const char *)_v2; - size_t offset; - - assertion_count(file, line); - if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0)) - return (1); - if (v1 == NULL || v2 == NULL) - return (0); - - failure_start(file, line, "%s != %s", e1, e2); - logprintf(" size %s = %d\n", ld, (int)l); - /* Dump 48 bytes (3 lines) so that the first difference is - * in the second line. */ - offset = 0; - while (l > 64 && memcmp(v1, v2, 32) == 0) { - /* Two lines agree, so step forward one line. */ - v1 += 16; - v2 += 16; - l -= 16; - offset += 16; - } - logprintf(" Dump of %s\n", e1); - hexdump(v1, v2, l < 128 ? l : 128, offset); - logprintf(" Dump of %s\n", e2); - hexdump(v2, v1, l < 128 ? l : 128, offset); - logprintf("\n"); - failure_finish(extra); - return (0); -} - -/* Verify that a block of memory is filled with the specified byte. */ -int -assertion_memory_filled_with(const char *file, int line, - const void *_v1, const char *vd, - size_t l, const char *ld, - char b, const char *bd, void *extra) -{ - const char *v1 = (const char *)_v1; - size_t c = 0; - size_t i; - (void)ld; /* UNUSED */ - - assertion_count(file, line); - - for (i = 0; i < l; ++i) { - if (v1[i] == b) { - ++c; - } - } - if (c == l) - return (1); - - failure_start(file, line, "%s (size %d) not filled with %s", vd, (int)l, bd); - logprintf(" Only %d bytes were correct\n", (int)c); - failure_finish(extra); - return (0); -} - -/* Verify that the named file exists and is empty. */ -int -assertion_empty_file(const char *filename, int line, const char *f1) -{ - char buff[1024]; - struct stat st; - ssize_t s; - FILE *f; - - assertion_count(filename, line); - - if (stat(f1, &st) != 0) { - failure_start(filename, line, "Stat failed: %s", f1); - failure_finish(NULL); - return (0); - } - if (st.st_size == 0) - return (1); - - failure_start(filename, line, "File should be empty: %s", f1); - logprintf(" File size: %d\n", (int)st.st_size); - logprintf(" Contents:\n"); - f = fopen(f1, "rb"); - if (f == NULL) { - logprintf(" Unable to open %s\n", f1); - } else { - s = ((off_t)sizeof(buff) < st.st_size) ? - (ssize_t)sizeof(buff) : (ssize_t)st.st_size; - s = fread(buff, 1, s, f); - hexdump(buff, NULL, s, 0); - fclose(f); - } - failure_finish(NULL); - return (0); -} - -/* Verify that the named file exists and is not empty. */ -int -assertion_non_empty_file(const char *filename, int line, const char *f1) -{ - struct stat st; - - assertion_count(filename, line); - - if (stat(f1, &st) != 0) { - failure_start(filename, line, "Stat failed: %s", f1); - failure_finish(NULL); - return (0); - } - if (st.st_size == 0) { - failure_start(filename, line, "File empty: %s", f1); - failure_finish(NULL); - return (0); - } - return (1); -} - -/* Verify that two files have the same contents. */ -/* TODO: hexdump the first bytes that actually differ. */ -int -assertion_equal_file(const char *filename, int line, const char *fn1, const char *fn2) -{ - char buff1[1024]; - char buff2[1024]; - FILE *f1, *f2; - int n1, n2; - - assertion_count(filename, line); - - f1 = fopen(fn1, "rb"); - f2 = fopen(fn2, "rb"); - if (f1 == NULL || f2 == NULL) { - if (f1) fclose(f1); - if (f2) fclose(f2); - return (0); - } - for (;;) { - n1 = (int)fread(buff1, 1, sizeof(buff1), f1); - n2 = (int)fread(buff2, 1, sizeof(buff2), f2); - if (n1 != n2) - break; - if (n1 == 0 && n2 == 0) { - fclose(f1); - fclose(f2); - return (1); - } - if (memcmp(buff1, buff2, n1) != 0) - break; - } - fclose(f1); - fclose(f2); - failure_start(filename, line, "Files not identical"); - logprintf(" file1=\"%s\"\n", fn1); - logprintf(" file2=\"%s\"\n", fn2); - failure_finish(NULL); - return (0); -} - -/* Verify that the named file does exist. */ -int -assertion_file_exists(const char *filename, int line, const char *f) -{ - assertion_count(filename, line); - -#if defined(_WIN32) && !defined(__CYGWIN__) - if (!_access(f, 0)) - return (1); -#else - if (!access(f, F_OK)) - return (1); -#endif - failure_start(filename, line, "File should exist: %s", f); - failure_finish(NULL); - return (0); -} - -/* Verify that the named file doesn't exist. */ -int -assertion_file_not_exists(const char *filename, int line, const char *f) -{ - assertion_count(filename, line); - -#if defined(_WIN32) && !defined(__CYGWIN__) - if (_access(f, 0)) - return (1); -#else - if (access(f, F_OK)) - return (1); -#endif - failure_start(filename, line, "File should not exist: %s", f); - failure_finish(NULL); - return (0); -} - -/* Compare the contents of a file to a block of memory. */ -int -assertion_file_contents(const char *filename, int line, const void *buff, int s, const char *fn) -{ - char *contents; - FILE *f; - int n; - - assertion_count(filename, line); - - f = fopen(fn, "rb"); - if (f == NULL) { - failure_start(filename, line, - "File should exist: %s", fn); - failure_finish(NULL); - return (0); - } - contents = malloc(s * 2); - n = (int)fread(contents, 1, s * 2, f); - fclose(f); - if (n == s && memcmp(buff, contents, s) == 0) { - free(contents); - return (1); - } - failure_start(filename, line, "File contents don't match"); - logprintf(" file=\"%s\"\n", fn); - if (n > 0) - hexdump(contents, buff, n > 512 ? 512 : n, 0); - else { - logprintf(" File empty, contents should be:\n"); - hexdump(buff, NULL, s > 512 ? 512 : s, 0); - } - failure_finish(NULL); - free(contents); - return (0); -} - -/* Check the contents of a text file, being tolerant of line endings. */ -int -assertion_text_file_contents(const char *filename, int line, const char *buff, const char *fn) -{ - char *contents; - const char *btxt, *ftxt; - FILE *f; - int n, s; - - assertion_count(filename, line); - f = fopen(fn, "r"); - if (f == NULL) { - failure_start(filename, line, - "File doesn't exist: %s", fn); - failure_finish(NULL); - return (0); - } - s = (int)strlen(buff); - contents = malloc(s * 2 + 128); - n = (int)fread(contents, 1, s * 2 + 128 - 1, f); - if (n >= 0) - contents[n] = '\0'; - fclose(f); - /* Compare texts. */ - btxt = buff; - ftxt = (const char *)contents; - while (*btxt != '\0' && *ftxt != '\0') { - if (*btxt == *ftxt) { - ++btxt; - ++ftxt; - continue; - } - if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') { - /* Pass over different new line characters. */ - ++btxt; - ftxt += 2; - continue; - } - break; - } - if (*btxt == '\0' && *ftxt == '\0') { - free(contents); - return (1); - } - failure_start(filename, line, "Contents don't match"); - logprintf(" file=\"%s\"\n", fn); - if (n > 0) { - hexdump(contents, buff, n, 0); - logprintf(" expected\n", fn); - hexdump(buff, contents, s, 0); - } else { - logprintf(" File empty, contents should be:\n"); - hexdump(buff, NULL, s, 0); - } - failure_finish(NULL); - free(contents); - return (0); -} - -/* Verify that a text file contains the specified lines, regardless of order */ -/* This could be more efficient if we sorted both sets of lines, etc, but - * since this is used only for testing and only ever deals with a dozen or so - * lines at a time, this relatively crude approach is just fine. */ -int -assertion_file_contains_lines_any_order(const char *file, int line, - const char *pathname, const char *lines[]) -{ - char *buff; - size_t buff_size; - size_t expected_count, actual_count, i, j; - char **expected = NULL; - char *p, **actual = NULL; - char c; - int expected_failure = 0, actual_failure = 0; - - assertion_count(file, line); - - buff = slurpfile(&buff_size, "%s", pathname); - if (buff == NULL) { - failure_start(pathname, line, "Can't read file: %s", pathname); - failure_finish(NULL); - return (0); - } - - /* Make a copy of the provided lines and count up the expected - * file size. */ - for (i = 0; lines[i] != NULL; ++i) { - } - expected_count = i; - if (expected_count) { - expected = malloc(sizeof(char *) * expected_count); - if (expected == NULL) { - failure_start(pathname, line, "Can't allocate memory"); - failure_finish(NULL); - free(expected); - return (0); - } - for (i = 0; lines[i] != NULL; ++i) { - expected[i] = strdup(lines[i]); - } - } - - /* Break the file into lines */ - actual_count = 0; - for (c = '\0', p = buff; p < buff + buff_size; ++p) { - if (*p == '\x0d' || *p == '\x0a') - *p = '\0'; - if (c == '\0' && *p != '\0') - ++actual_count; - c = *p; - } - if (actual_count) { - actual = calloc(sizeof(char *), actual_count); - if (actual == NULL) { - failure_start(pathname, line, "Can't allocate memory"); - failure_finish(NULL); - free(expected); - return (0); - } - for (j = 0, p = buff; p < buff + buff_size; - p += 1 + strlen(p)) { - if (*p != '\0') { - actual[j] = p; - ++j; - } - } - } - - /* Erase matching lines from both lists */ - for (i = 0; i < expected_count; ++i) { - if (expected[i] == NULL) - continue; - for (j = 0; j < actual_count; ++j) { - if (actual[j] == NULL) - continue; - if (strcmp(expected[i], actual[j]) == 0) { - free(expected[i]); - expected[i] = NULL; - actual[j] = NULL; - break; - } - } - } - - /* If there's anything left, it's a failure */ - for (i = 0; i < expected_count; ++i) { - if (expected[i] != NULL) - ++expected_failure; - } - for (j = 0; j < actual_count; ++j) { - if (actual[j] != NULL) - ++actual_failure; - } - if (expected_failure == 0 && actual_failure == 0) { - free(buff); - free(expected); - free(actual); - return (1); - } - failure_start(file, line, "File doesn't match: %s", pathname); - for (i = 0; i < expected_count; ++i) { - if (expected[i] != NULL) { - logprintf(" Expected but not present: %s\n", expected[i]); - free(expected[i]); - } - } - for (j = 0; j < actual_count; ++j) { - if (actual[j] != NULL) - logprintf(" Present but not expected: %s\n", actual[j]); - } - failure_finish(NULL); - free(buff); - free(expected); - free(actual); - return (0); -} - -/* Verify that a text file does not contains the specified strings */ -int -assertion_file_contains_no_invalid_strings(const char *file, int line, - const char *pathname, const char *strings[]) -{ - char *buff; - int i; - - buff = slurpfile(NULL, "%s", pathname); - if (buff == NULL) { - failure_start(file, line, "Can't read file: %s", pathname); - failure_finish(NULL); - return (0); - } - - for (i = 0; strings[i] != NULL; ++i) { - if (strstr(buff, strings[i]) != NULL) { - failure_start(file, line, "Invalid string in %s: %s", pathname, - strings[i]); - failure_finish(NULL); - free(buff); - return(0); - } - } - - free(buff); - return (0); -} - -/* Test that two paths point to the same file. */ -/* As a side-effect, asserts that both files exist. */ -static int -is_hardlink(const char *file, int line, - const char *path1, const char *path2) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2; - int r; - - assertion_count(file, line); - r = my_GetFileInformationByName(path1, &bhfi1); - if (r == 0) { - failure_start(file, line, "File %s can't be inspected?", path1); - failure_finish(NULL); - return (0); - } - r = my_GetFileInformationByName(path2, &bhfi2); - if (r == 0) { - failure_start(file, line, "File %s can't be inspected?", path2); - failure_finish(NULL); - return (0); - } - return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber - && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh - && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow); -#else - struct stat st1, st2; - int r; - - assertion_count(file, line); - r = lstat(path1, &st1); - if (r != 0) { - failure_start(file, line, "File should exist: %s", path1); - failure_finish(NULL); - return (0); - } - r = lstat(path2, &st2); - if (r != 0) { - failure_start(file, line, "File should exist: %s", path2); - failure_finish(NULL); - return (0); - } - return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev); -#endif -} - -int -assertion_is_hardlink(const char *file, int line, - const char *path1, const char *path2) -{ - if (is_hardlink(file, line, path1, path2)) - return (1); - failure_start(file, line, - "Files %s and %s are not hardlinked", path1, path2); - failure_finish(NULL); - return (0); -} - -int -assertion_is_not_hardlink(const char *file, int line, - const char *path1, const char *path2) -{ - if (!is_hardlink(file, line, path1, path2)) - return (1); - failure_start(file, line, - "Files %s and %s should not be hardlinked", path1, path2); - failure_finish(NULL); - return (0); -} - -/* Verify a/b/mtime of 'pathname'. */ -/* If 'recent', verify that it's within last 10 seconds. */ -static int -assertion_file_time(const char *file, int line, - const char *pathname, long t, long nsec, char type, int recent) -{ - long long filet, filet_nsec; - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) -#define EPOC_TIME (116444736000000000ULL) - FILETIME fxtime, fbirthtime, fatime, fmtime; - ULARGE_INTEGER wintm; - HANDLE h; - fxtime.dwLowDateTime = 0; - fxtime.dwHighDateTime = 0; - - assertion_count(file, line); - /* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open - * a directory file. If not, CreateFile() will fail when - * the pathname is a directory. */ - h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) { - failure_start(file, line, "Can't access %s\n", pathname); - failure_finish(NULL); - return (0); - } - r = GetFileTime(h, &fbirthtime, &fatime, &fmtime); - switch (type) { - case 'a': fxtime = fatime; break; - case 'b': fxtime = fbirthtime; break; - case 'm': fxtime = fmtime; break; - } - CloseHandle(h); - if (r == 0) { - failure_start(file, line, "Can't GetFileTime %s\n", pathname); - failure_finish(NULL); - return (0); - } - wintm.LowPart = fxtime.dwLowDateTime; - wintm.HighPart = fxtime.dwHighDateTime; - filet = (wintm.QuadPart - EPOC_TIME) / 10000000; - filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100; - nsec = (nsec / 100) * 100; /* Round the request */ -#else - struct stat st; - - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0) { - failure_start(file, line, "Can't stat %s\n", pathname); - failure_finish(NULL); - return (0); - } - switch (type) { - case 'a': filet = st.st_atime; break; - case 'm': filet = st.st_mtime; break; - case 'b': filet = 0; break; - default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); - exit(1); - } -#if defined(__FreeBSD__) - switch (type) { - case 'a': filet_nsec = st.st_atimespec.tv_nsec; break; - case 'b': filet = st.st_birthtime; - /* FreeBSD filesystems that don't support birthtime - * (e.g., UFS1) always return -1 here. */ - if (filet == -1) { - return (1); - } - filet_nsec = st.st_birthtimespec.tv_nsec; break; - case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break; - default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); - exit(1); - } - /* FreeBSD generally only stores to microsecond res, so round. */ - filet_nsec = (filet_nsec / 1000) * 1000; - nsec = (nsec / 1000) * 1000; -#else - filet_nsec = nsec = 0; /* Generic POSIX only has whole seconds. */ - if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */ -#if defined(__HAIKU__) - if (type == 'a') return (1); /* Haiku doesn't have atime. */ -#endif -#endif -#endif - if (recent) { - /* Check that requested time is up-to-date. */ - time_t now = time(NULL); - if (filet < now - 10 || filet > now + 1) { - failure_start(file, line, - "File %s has %ctime %lld, %lld seconds ago\n", - pathname, type, filet, now - filet); - failure_finish(NULL); - return (0); - } - } else if (filet != t || filet_nsec != nsec) { - failure_start(file, line, - "File %s has %ctime %lld.%09lld, expected %lld.%09lld", - pathname, type, filet, filet_nsec, t, nsec); - failure_finish(NULL); - return (0); - } - return (1); -} - -/* Verify atime of 'pathname'. */ -int -assertion_file_atime(const char *file, int line, - const char *pathname, long t, long nsec) -{ - return assertion_file_time(file, line, pathname, t, nsec, 'a', 0); -} - -/* Verify atime of 'pathname' is up-to-date. */ -int -assertion_file_atime_recent(const char *file, int line, const char *pathname) -{ - return assertion_file_time(file, line, pathname, 0, 0, 'a', 1); -} - -/* Verify birthtime of 'pathname'. */ -int -assertion_file_birthtime(const char *file, int line, - const char *pathname, long t, long nsec) -{ - return assertion_file_time(file, line, pathname, t, nsec, 'b', 0); -} - -/* Verify birthtime of 'pathname' is up-to-date. */ -int -assertion_file_birthtime_recent(const char *file, int line, - const char *pathname) -{ - return assertion_file_time(file, line, pathname, 0, 0, 'b', 1); -} - -/* Verify mode of 'pathname'. */ -int -assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode) -{ - int mode; - int r; - - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - failure_start(file, line, "assertFileMode not yet implemented for Windows"); - (void)mode; /* UNUSED */ - (void)r; /* UNUSED */ -#else - { - struct stat st; - r = lstat(pathname, &st); - mode = (int)(st.st_mode & 0777); - } - if (r == 0 && mode == expected_mode) - return (1); - failure_start(file, line, "File %s has mode %o, expected %o", - pathname, mode, expected_mode); -#endif - failure_finish(NULL); - return (0); -} - -/* Verify mtime of 'pathname'. */ -int -assertion_file_mtime(const char *file, int line, - const char *pathname, long t, long nsec) -{ - return assertion_file_time(file, line, pathname, t, nsec, 'm', 0); -} - -/* Verify mtime of 'pathname' is up-to-date. */ -int -assertion_file_mtime_recent(const char *file, int line, const char *pathname) -{ - return assertion_file_time(file, line, pathname, 0, 0, 'm', 1); -} - -/* Verify number of links to 'pathname'. */ -int -assertion_file_nlinks(const char *file, int line, - const char *pathname, int nlinks) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - BY_HANDLE_FILE_INFORMATION bhfi; - int r; - - assertion_count(file, line); - r = my_GetFileInformationByName(pathname, &bhfi); - if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks) - return (1); - failure_start(file, line, "File %s has %d links, expected %d", - pathname, bhfi.nNumberOfLinks, nlinks); - failure_finish(NULL); - return (0); -#else - struct stat st; - int r; - - assertion_count(file, line); - r = lstat(pathname, &st); - if (r == 0 && (int)st.st_nlink == nlinks) - return (1); - failure_start(file, line, "File %s has %d links, expected %d", - pathname, st.st_nlink, nlinks); - failure_finish(NULL); - return (0); -#endif -} - -/* Verify size of 'pathname'. */ -int -assertion_file_size(const char *file, int line, const char *pathname, long size) -{ - int64_t filesize; - int r; - - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - { - BY_HANDLE_FILE_INFORMATION bhfi; - r = !my_GetFileInformationByName(pathname, &bhfi); - filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow; - } -#else - { - struct stat st; - r = lstat(pathname, &st); - filesize = st.st_size; - } -#endif - if (r == 0 && filesize == size) - return (1); - failure_start(file, line, "File %s has size %ld, expected %ld", - pathname, (long)filesize, (long)size); - failure_finish(NULL); - return (0); -} - -/* Assert that 'pathname' is a dir. If mode >= 0, verify that too. */ -int -assertion_is_dir(const char *file, int line, const char *pathname, int mode) -{ - struct stat st; - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)mode; /* UNUSED */ -#endif - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0) { - failure_start(file, line, "Dir should exist: %s", pathname); - failure_finish(NULL); - return (0); - } - if (!S_ISDIR(st.st_mode)) { - failure_start(file, line, "%s is not a dir", pathname); - failure_finish(NULL); - return (0); - } -#if !defined(_WIN32) || defined(__CYGWIN__) - /* Windows doesn't handle permissions the same way as POSIX, - * so just ignore the mode tests. */ - /* TODO: Can we do better here? */ - if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { - failure_start(file, line, "Dir %s has wrong mode", pathname); - logprintf(" Expected: 0%3o\n", mode); - logprintf(" Found: 0%3o\n", st.st_mode & 07777); - failure_finish(NULL); - return (0); - } -#endif - return (1); -} - -/* Verify that 'pathname' is a regular file. If 'mode' is >= 0, - * verify that too. */ -int -assertion_is_reg(const char *file, int line, const char *pathname, int mode) -{ - struct stat st; - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)mode; /* UNUSED */ -#endif - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0 || !S_ISREG(st.st_mode)) { - failure_start(file, line, "File should exist: %s", pathname); - failure_finish(NULL); - return (0); - } -#if !defined(_WIN32) || defined(__CYGWIN__) - /* Windows doesn't handle permissions the same way as POSIX, - * so just ignore the mode tests. */ - /* TODO: Can we do better here? */ - if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { - failure_start(file, line, "File %s has wrong mode", pathname); - logprintf(" Expected: 0%3o\n", mode); - logprintf(" Found: 0%3o\n", st.st_mode & 07777); - failure_finish(NULL); - return (0); - } -#endif - return (1); -} - -/* Check whether 'pathname' is a symbolic link. If 'contents' is - * non-NULL, verify that the symlink has those contents. */ -static int -is_symlink(const char *file, int line, - const char *pathname, const char *contents) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)pathname; /* UNUSED */ - (void)contents; /* UNUSED */ - assertion_count(file, line); - /* Windows sort-of has real symlinks, but they're only usable - * by privileged users and are crippled even then, so there's - * really not much point in bothering with this. */ - return (0); -#else - char buff[300]; - struct stat st; - ssize_t linklen; - int r; - - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0) { - failure_start(file, line, - "Symlink should exist: %s", pathname); - failure_finish(NULL); - return (0); - } - if (!S_ISLNK(st.st_mode)) - return (0); - if (contents == NULL) - return (1); - linklen = readlink(pathname, buff, sizeof(buff)); - if (linklen < 0) { - failure_start(file, line, "Can't read symlink %s", pathname); - failure_finish(NULL); - return (0); - } - buff[linklen] = '\0'; - if (strcmp(buff, contents) != 0) - return (0); - return (1); -#endif -} - -/* Assert that path is a symlink that (optionally) contains contents. */ -int -assertion_is_symlink(const char *file, int line, - const char *path, const char *contents) -{ - if (is_symlink(file, line, path, contents)) - return (1); - if (contents) - failure_start(file, line, "File %s is not a symlink to %s", - path, contents); - else - failure_start(file, line, "File %s is not a symlink", path); - failure_finish(NULL); - return (0); -} - - -/* Create a directory and report any errors. */ -int -assertion_make_dir(const char *file, int line, const char *dirname, int mode) -{ - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)mode; /* UNUSED */ - if (0 == _mkdir(dirname)) - return (1); -#else - if (0 == mkdir(dirname, mode)) { - if (0 == chmod(dirname, mode)) { - assertion_file_mode(file, line, dirname, mode); - return (1); - } - } -#endif - failure_start(file, line, "Could not create directory %s", dirname); - failure_finish(NULL); - return(0); -} - -/* Create a file with the specified contents and report any failures. */ -int -assertion_make_file(const char *file, int line, - const char *path, int mode, int csize, const void *contents) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* TODO: Rework this to set file mode as well. */ - FILE *f; - (void)mode; /* UNUSED */ - assertion_count(file, line); - f = fopen(path, "wb"); - if (f == NULL) { - failure_start(file, line, "Could not create file %s", path); - failure_finish(NULL); - return (0); - } - if (contents != NULL) { - size_t wsize; - - if (csize < 0) - wsize = strlen(contents); - else - wsize = (size_t)csize; - if (wsize != fwrite(contents, 1, wsize, f)) { - fclose(f); - failure_start(file, line, - "Could not write file %s", path); - failure_finish(NULL); - return (0); - } - } - fclose(f); - return (1); -#else - int fd; - assertion_count(file, line); - fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644); - if (fd < 0) { - failure_start(file, line, "Could not create %s", path); - failure_finish(NULL); - return (0); - } - if (0 != chmod(path, mode)) { - failure_start(file, line, "Could not chmod %s", path); - failure_finish(NULL); - close(fd); - return (0); - } - if (contents != NULL) { - ssize_t wsize; - - if (csize < 0) - wsize = (ssize_t)strlen(contents); - else - wsize = (ssize_t)csize; - if (wsize != write(fd, contents, wsize)) { - close(fd); - failure_start(file, line, - "Could not write to %s", path); - failure_finish(NULL); - close(fd); - return (0); - } - } - close(fd); - assertion_file_mode(file, line, path, mode); - return (1); -#endif -} - -/* Create a hardlink and report any failures. */ -int -assertion_make_hardlink(const char *file, int line, - const char *newpath, const char *linkto) -{ - int succeeded; - - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - succeeded = my_CreateHardLinkA(newpath, linkto); -#elif HAVE_LINK - succeeded = !link(linkto, newpath); -#else - succeeded = 0; -#endif - if (succeeded) - return (1); - failure_start(file, line, "Could not create hardlink"); - logprintf(" New link: %s\n", newpath); - logprintf(" Old name: %s\n", linkto); - failure_finish(NULL); - return(0); -} - -/* Create a symlink and report any failures. */ -int -assertion_make_symlink(const char *file, int line, - const char *newpath, const char *linkto) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - int targetIsDir = 0; /* TODO: Fix this */ - assertion_count(file, line); - if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir)) - return (1); -#elif HAVE_SYMLINK - assertion_count(file, line); - if (0 == symlink(linkto, newpath)) - return (1); -#endif - failure_start(file, line, "Could not create symlink"); - logprintf(" New link: %s\n", newpath); - logprintf(" Old name: %s\n", linkto); - failure_finish(NULL); - return(0); -} - -/* Set umask, report failures. */ -int -assertion_umask(const char *file, int line, int mask) -{ - assertion_count(file, line); - (void)file; /* UNUSED */ - (void)line; /* UNUSED */ - umask(mask); - return (1); -} - -/* Set times, report failures. */ -int -assertion_utimes(const char *file, int line, - const char *pathname, long at, long at_nsec, long mt, long mt_nsec) -{ - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) -#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\ - + (((nsec)/1000)*10)) - HANDLE h; - ULARGE_INTEGER wintm; - FILETIME fatime, fmtime; - FILETIME *pat, *pmt; - - assertion_count(file, line); - h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) { - failure_start(file, line, "Can't access %s\n", pathname); - failure_finish(NULL); - return (0); - } - - if (at > 0 || at_nsec > 0) { - wintm.QuadPart = WINTIME(at, at_nsec); - fatime.dwLowDateTime = wintm.LowPart; - fatime.dwHighDateTime = wintm.HighPart; - pat = &fatime; - } else - pat = NULL; - if (mt > 0 || mt_nsec > 0) { - wintm.QuadPart = WINTIME(mt, mt_nsec); - fmtime.dwLowDateTime = wintm.LowPart; - fmtime.dwHighDateTime = wintm.HighPart; - pmt = &fmtime; - } else - pmt = NULL; - if (pat != NULL || pmt != NULL) - r = SetFileTime(h, NULL, pat, pmt); - else - r = 1; - CloseHandle(h); - if (r == 0) { - failure_start(file, line, "Can't SetFileTime %s\n", pathname); - failure_finish(NULL); - return (0); - } - return (1); -#else /* defined(_WIN32) && !defined(__CYGWIN__) */ - struct stat st; - struct timeval times[2]; - -#if !defined(__FreeBSD__) - mt_nsec = at_nsec = 0; /* Generic POSIX only has whole seconds. */ -#endif - if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0) - return (1); - - r = lstat(pathname, &st); - if (r < 0) { - failure_start(file, line, "Can't stat %s\n", pathname); - failure_finish(NULL); - return (0); - } - - if (mt == 0 && mt_nsec == 0) { - mt = st.st_mtime; -#if defined(__FreeBSD__) - mt_nsec = st.st_mtimespec.tv_nsec; - /* FreeBSD generally only stores to microsecond res, so round. */ - mt_nsec = (mt_nsec / 1000) * 1000; -#endif - } - if (at == 0 && at_nsec == 0) { - at = st.st_atime; -#if defined(__FreeBSD__) - at_nsec = st.st_atimespec.tv_nsec; - /* FreeBSD generally only stores to microsecond res, so round. */ - at_nsec = (at_nsec / 1000) * 1000; -#endif - } - - times[1].tv_sec = mt; - times[1].tv_usec = mt_nsec / 1000; - - times[0].tv_sec = at; - times[0].tv_usec = at_nsec / 1000; - -#ifdef HAVE_LUTIMES - r = lutimes(pathname, times); -#else - r = utimes(pathname, times); -#endif - if (r < 0) { - failure_start(file, line, "Can't utimes %s\n", pathname); - failure_finish(NULL); - return (0); - } - return (1); -#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ -} - -/* Set nodump, report failures. */ -int -assertion_nodump(const char *file, int line, const char *pathname) -{ -#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) - int r; - - assertion_count(file, line); - r = chflags(pathname, UF_NODUMP); - if (r < 0) { - failure_start(file, line, "Can't set nodump %s\n", pathname); - failure_finish(NULL); - return (0); - } -#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ - && defined(EXT2_NODUMP_FL) - int fd, r, flags; - - assertion_count(file, line); - fd = open(pathname, O_RDONLY | O_NONBLOCK); - if (fd < 0) { - failure_start(file, line, "Can't open %s\n", pathname); - failure_finish(NULL); - return (0); - } - r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); - if (r < 0) { - failure_start(file, line, "Can't get flags %s\n", pathname); - failure_finish(NULL); - return (0); - } - flags |= EXT2_NODUMP_FL; - r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); - if (r < 0) { - failure_start(file, line, "Can't set nodump %s\n", pathname); - failure_finish(NULL); - return (0); - } - close(fd); -#else - (void)pathname; /* UNUSED */ - assertion_count(file, line); -#endif - return (1); -} - -/* - * - * UTILITIES for use by tests. - * - */ - -/* - * Check whether platform supports symlinks. This is intended - * for tests to use in deciding whether to bother testing symlink - * support; if the platform doesn't support symlinks, there's no point - * in checking whether the program being tested can create them. - * - * Note that the first time this test is called, we actually go out to - * disk to create and verify a symlink. This is necessary because - * symlink support is actually a property of a particular filesystem - * and can thus vary between directories on a single system. After - * the first call, this returns the cached result from memory, so it's - * safe to call it as often as you wish. - */ -int -canSymlink(void) -{ - /* Remember the test result */ - static int value = 0, tested = 0; - if (tested) - return (value); - - ++tested; - assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a"); - /* Note: Cygwin has its own symlink() emulation that does not - * use the Win32 CreateSymbolicLink() function. */ -#if defined(_WIN32) && !defined(__CYGWIN__) - value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0) - && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0"); -#elif HAVE_SYMLINK - value = (0 == symlink("canSymlink.0", "canSymlink.1")) - && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0"); -#endif - return (value); -} - -/* Platform-dependent options for hiding the output of a subcommand. */ -#if defined(_WIN32) && !defined(__CYGWIN__) -static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */ -#else -static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */ -#endif -/* - * Can this platform run the bzip2 program? - */ -int -canBzip2(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("bzip2 -d -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the grzip program? - */ -int -canGrzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("grzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the gzip program? - */ -int -canGzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("gzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lrzip program? - */ -int -canRunCommand(const char *cmd) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("%s %s", cmd, redirectArgs) == 0) - value = 1; - } - return (value); -} - -int -canLrzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lrzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lz4 program? - */ -int -canLz4(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lz4 -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lzip program? - */ -int -canLzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lzma program? - */ -int -canLzma(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzma -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lzop program? - */ -int -canLzop(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzop -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the xz program? - */ -int -canXz(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("xz -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this filesystem handle nodump flags. - */ -#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) - -int -canNodump(void) -{ - const char *path = "cannodumptest"; - struct stat sb; - - assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); - if (chflags(path, UF_NODUMP) < 0) - return (0); - if (stat(path, &sb) < 0) - return (0); - if (sb.st_flags & UF_NODUMP) - return (1); - return (0); -} - -#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ - && defined(EXT2_NODUMP_FL) - -int -canNodump(void) -{ - const char *path = "cannodumptest"; - int fd, r, flags; - - assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) - return (0); - r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); - if (r < 0) - return (0); - flags |= EXT2_NODUMP_FL; - r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); - if (r < 0) - return (0); - close(fd); - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) - return (0); - r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); - if (r < 0) - return (0); - close(fd); - if (flags & EXT2_NODUMP_FL) - return (1); - return (0); -} - -#else - -int -canNodump() -{ - return (0); -} - -#endif - -/* - * Sleep as needed; useful for verifying disk timestamp changes by - * ensuring that the wall-clock time has actually changed before we - * go back to re-read something from disk. - */ -void -sleepUntilAfter(time_t t) -{ - while (t >= time(NULL)) -#if defined(_WIN32) && !defined(__CYGWIN__) - Sleep(500); -#else - sleep(1); -#endif -} - -/* - * Call standard system() call, but build up the command line using - * sprintf() conventions. - */ -int -systemf(const char *fmt, ...) -{ - char buff[8192]; - va_list ap; - int r; - - va_start(ap, fmt); - vsprintf(buff, fmt, ap); - if (verbosity > VERBOSITY_FULL) - logprintf("Cmd: %s\n", buff); - r = system(buff); - va_end(ap); - return (r); -} - -/* - * Slurp a file into memory for ease of comparison and testing. - * Returns size of file in 'sizep' if non-NULL, null-terminates - * data in memory for ease of use. - */ -char * -slurpfile(size_t * sizep, const char *fmt, ...) -{ - char filename[8192]; - struct stat st; - va_list ap; - char *p; - ssize_t bytes_read; - FILE *f; - int r; - - va_start(ap, fmt); - vsprintf(filename, fmt, ap); - va_end(ap); - - f = fopen(filename, "rb"); - if (f == NULL) { - /* Note: No error; non-existent file is okay here. */ - return (NULL); - } - r = fstat(fileno(f), &st); - if (r != 0) { - logprintf("Can't stat file %s\n", filename); - fclose(f); - return (NULL); - } - p = malloc((size_t)st.st_size + 1); - if (p == NULL) { - logprintf("Can't allocate %ld bytes of memory to read file %s\n", - (long int)st.st_size, filename); - fclose(f); - return (NULL); - } - bytes_read = fread(p, 1, (size_t)st.st_size, f); - if (bytes_read < st.st_size) { - logprintf("Can't read file %s\n", filename); - fclose(f); - free(p); - return (NULL); - } - p[st.st_size] = '\0'; - if (sizep != NULL) - *sizep = (size_t)st.st_size; - fclose(f); - return (p); -} - -/* - * Slurp a file into memory for ease of comparison and testing. - * Returns size of file in 'sizep' if non-NULL, null-terminates - * data in memory for ease of use. - */ -void -dumpfile(const char *filename, void *data, size_t len) -{ - ssize_t bytes_written; - FILE *f; - - f = fopen(filename, "wb"); - if (f == NULL) { - logprintf("Can't open file %s for writing\n", filename); - return; - } - bytes_written = fwrite(data, 1, len, f); - if (bytes_written < (ssize_t)len) - logprintf("Can't write file %s\n", filename); - fclose(f); -} - -/* Read a uuencoded file from the reference directory, decode, and - * write the result into the current directory. */ -#define VALID_UUDECODE(c) (c >= 32 && c <= 96) -#define UUDECODE(c) (((c) - 0x20) & 0x3f) -void -extract_reference_file(const char *name) -{ - char buff[1024]; - FILE *in, *out; - - sprintf(buff, "%s/%s.uu", refdir, name); - in = fopen(buff, "r"); - failure("Couldn't open reference file %s", buff); - assert(in != NULL); - if (in == NULL) - return; - /* Read up to and including the 'begin' line. */ - for (;;) { - if (fgets(buff, sizeof(buff), in) == NULL) { - /* TODO: This is a failure. */ - return; - } - if (memcmp(buff, "begin ", 6) == 0) - break; - } - /* Now, decode the rest and write it. */ - out = fopen(name, "wb"); - while (fgets(buff, sizeof(buff), in) != NULL) { - char *p = buff; - int bytes; - - if (memcmp(buff, "end", 3) == 0) - break; - - bytes = UUDECODE(*p++); - while (bytes > 0) { - int n = 0; - /* Write out 1-3 bytes from that. */ - if (bytes > 0) { - assert(VALID_UUDECODE(p[0])); - assert(VALID_UUDECODE(p[1])); - n = UUDECODE(*p++) << 18; - n |= UUDECODE(*p++) << 12; - fputc(n >> 16, out); - --bytes; - } - if (bytes > 0) { - assert(VALID_UUDECODE(p[0])); - n |= UUDECODE(*p++) << 6; - fputc((n >> 8) & 0xFF, out); - --bytes; - } - if (bytes > 0) { - assert(VALID_UUDECODE(p[0])); - n |= UUDECODE(*p++); - fputc(n & 0xFF, out); - --bytes; - } - } - } - fclose(out); - fclose(in); -} - -void -copy_reference_file(const char *name) -{ - char buff[1024]; - FILE *in, *out; - size_t rbytes; - - sprintf(buff, "%s/%s", refdir, name); - in = fopen(buff, "rb"); - failure("Couldn't open reference file %s", buff); - assert(in != NULL); - if (in == NULL) - return; - /* Now, decode the rest and write it. */ - /* Not a lot of error checking here; the input better be right. */ - out = fopen(name, "wb"); - while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) { - if (fwrite(buff, 1, rbytes, out) != rbytes) { - logprintf("Error: fwrite\n"); - break; - } - } - fclose(out); - fclose(in); -} - -int -is_LargeInode(const char *file) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - BY_HANDLE_FILE_INFORMATION bhfi; - int r; - - r = my_GetFileInformationByName(file, &bhfi); - if (r != 0) - return (0); - return (bhfi.nFileIndexHigh & 0x0000FFFFUL); -#else - struct stat st; - int64_t ino; - - if (stat(file, &st) < 0) - return (0); - ino = (int64_t)st.st_ino; - return (ino > 0xffffffff); -#endif -} - -void -extract_reference_files(const char **names) -{ - while (names && *names) - extract_reference_file(*names++); -} - -/* - * - * TEST management - * - */ - -/* - * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has - * a line like - * DEFINE_TEST(test_function) - * for each test. - */ - -/* Use "list.h" to declare all of the test functions. */ -#undef DEFINE_TEST -#define DEFINE_TEST(name) void name(void); -#include "list.h" - -/* Use "list.h" to create a list of all tests (functions and names). */ -#undef DEFINE_TEST -#define DEFINE_TEST(n) { n, #n, 0 }, -struct test_list_t tests[] = { - #include "list.h" -}; - -/* - * Summarize repeated failures in the just-completed test. - */ -static void -test_summarize(int failed, int skips_num) -{ - unsigned int i; - - switch (verbosity) { - case VERBOSITY_SUMMARY_ONLY: - printf(failed ? "E" : "."); - fflush(stdout); - break; - case VERBOSITY_PASSFAIL: - printf(failed ? "FAIL\n" : skips_num ? "ok (S)\n" : "ok\n"); - break; - } - - log_console = (verbosity == VERBOSITY_LIGHT_REPORT); - - for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { - if (failed_lines[i].count > 1 && !failed_lines[i].skip) - logprintf("%s:%d: Summary: Failed %d times\n", - failed_filename, i, failed_lines[i].count); - } - /* Clear the failure history for the next file. */ - failed_filename = NULL; - memset(failed_lines, 0, sizeof(failed_lines)); -} - -/* - * Actually run a single test, with appropriate setup and cleanup. - */ -static int -test_run(int i, const char *tmpdir) -{ - char workdir[1024]; - char logfilename[64]; - int failures_before = failures; - int skips_before = skips; - int oldumask; - - switch (verbosity) { - case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */ - break; - case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */ - printf("%3d: %-64s", i, tests[i].name); - fflush(stdout); - break; - default: /* Title of test, details will follow */ - printf("%3d: %s\n", i, tests[i].name); - } - - /* Chdir to the top-level work directory. */ - if (!assertChdir(tmpdir)) { - fprintf(stderr, - "ERROR: Can't chdir to top work dir %s\n", tmpdir); - exit(1); - } - /* Create a log file for this test. */ - sprintf(logfilename, "%s.log", tests[i].name); - logfile = fopen(logfilename, "w"); - fprintf(logfile, "%s\n\n", tests[i].name); - /* Chdir() to a work dir for this specific test. */ - snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name); - testworkdir = workdir; - if (!assertMakeDir(testworkdir, 0755) - || !assertChdir(testworkdir)) { - fprintf(stderr, - "ERROR: Can't chdir to work dir %s\n", testworkdir); - exit(1); - } - /* Explicitly reset the locale before each test. */ - setlocale(LC_ALL, "C"); - /* Record the umask before we run the test. */ - umask(oldumask = umask(0)); - /* - * Run the actual test. - */ - (*tests[i].func)(); - /* - * Clean up and report afterwards. - */ - testworkdir = NULL; - /* Restore umask */ - umask(oldumask); - /* Reset locale. */ - setlocale(LC_ALL, "C"); - /* Reset directory. */ - if (!assertChdir(tmpdir)) { - fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n", - tmpdir); - exit(1); - } - /* Report per-test summaries. */ - tests[i].failures = failures - failures_before; - test_summarize(tests[i].failures, skips - skips_before); - /* Close the per-test log file. */ - fclose(logfile); - logfile = NULL; - /* If there were no failures, we can remove the work dir and logfile. */ - if (tests[i].failures == 0) { - if (!keep_temp_files && assertChdir(tmpdir)) { -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure not to leave empty directories. - * Sometimes a processing of closing files used by tests - * is not done, then rmdir will be failed and it will - * leave a empty test directory. So we should wait a few - * seconds and retry rmdir. */ - int r, t; - for (t = 0; t < 10; t++) { - if (t > 0) - Sleep(1000); - r = systemf("rmdir /S /Q %s", tests[i].name); - if (r == 0) - break; - } - systemf("del %s", logfilename); -#else - systemf("rm -rf %s", tests[i].name); - systemf("rm %s", logfilename); -#endif - } - } - /* Return appropriate status. */ - return (tests[i].failures); -} - -/* - * - * - * MAIN and support routines. - * - * - */ - -static void -usage(const char *program) -{ - static const int limit = sizeof(tests) / sizeof(tests[0]); - int i; - - printf("Usage: %s [options] <test> <test> ...\n", program); - printf("Default is to run all tests.\n"); - printf("Otherwise, specify the numbers of the tests you wish to run.\n"); - printf("Options:\n"); - printf(" -d Dump core after any failure, for debugging.\n"); - printf(" -k Keep all temp files.\n"); - printf(" Default: temp files for successful tests deleted.\n"); -#ifdef PROGRAM - printf(" -p <path> Path to executable to be tested.\n"); - printf(" Default: path taken from " ENVBASE " environment variable.\n"); -#endif - printf(" -q Quiet.\n"); - printf(" -r <dir> Path to dir containing reference files.\n"); - printf(" Default: Current directory.\n"); - printf(" -u Keep running specifies tests until one fails.\n"); - printf(" -v Verbose.\n"); - printf("Available tests:\n"); - for (i = 0; i < limit; i++) - printf(" %d: %s\n", i, tests[i].name); - exit(1); -} - -static char * -get_refdir(const char *d) -{ - size_t tried_size, buff_size; - char *buff, *tried, *pwd = NULL, *p = NULL; - -#ifdef PATH_MAX - buff_size = PATH_MAX; -#else - buff_size = 8192; -#endif - buff = calloc(buff_size, 1); - if (buff == NULL) { - fprintf(stderr, "Unable to allocate memory\n"); - exit(1); - } - - /* Allocate a buffer to hold the various directories we checked. */ - tried_size = buff_size * 2; - tried = calloc(tried_size, 1); - if (tried == NULL) { - fprintf(stderr, "Unable to allocate memory\n"); - exit(1); - } - - /* If a dir was specified, try that */ - if (d != NULL) { - pwd = NULL; - snprintf(buff, buff_size, "%s", d); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - goto failure; - } - - /* Get the current dir. */ -#ifdef PATH_MAX - pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ -#else - pwd = getcwd(NULL, 0); -#endif - while (pwd[strlen(pwd) - 1] == '\n') - pwd[strlen(pwd) - 1] = '\0'; - - /* Look for a known file. */ - snprintf(buff, buff_size, "%s", pwd); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - - snprintf(buff, buff_size, "%s/test", pwd); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - -#if defined(LIBRARY) - snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY); -#else - snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM); -#endif - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - -#if defined(PROGRAM_ALIAS) - snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); -#endif - - if (memcmp(pwd, "/usr/obj", 8) == 0) { - snprintf(buff, buff_size, "%s", pwd + 8); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - - snprintf(buff, buff_size, "%s/test", pwd + 8); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - } - -failure: - printf("Unable to locate known reference file %s\n", KNOWNREF); - printf(" Checked following directories:\n%s\n", tried); - printf("Use -r option to specify full path to reference directory\n"); -#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) - DebugBreak(); -#endif - exit(1); - -success: - free(p); - free(pwd); - free(tried); - - /* Copy result into a fresh buffer to reduce memory usage. */ - p = strdup(buff); - free(buff); - return p; -} - -int -main(int argc, char **argv) -{ - static const int limit = sizeof(tests) / sizeof(tests[0]); - int test_set[sizeof(tests) / sizeof(tests[0])]; - int i = 0, j = 0, tests_run = 0, tests_failed = 0, option; - time_t now; - char *refdir_alloc = NULL; - const char *progname; - char **saved_argv; - const char *tmp, *option_arg, *p; - char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL; - char tmpdir_timestamp[256]; - - (void)argc; /* UNUSED */ - - /* Get the current dir. */ -#ifdef PATH_MAX - pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ -#else - pwd = getcwd(NULL, 0); -#endif - while (pwd[strlen(pwd) - 1] == '\n') - pwd[strlen(pwd) - 1] = '\0'; - -#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__) - /* To stop to run the default invalid parameter handler. */ - _set_invalid_parameter_handler(invalid_parameter_handler); - /* Disable annoying assertion message box. */ - _CrtSetReportMode(_CRT_ASSERT, 0); -#endif - - /* - * Name of this program, used to build root of our temp directory - * tree. - */ - progname = p = argv[0]; - if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL) - { - fprintf(stderr, "ERROR: Out of memory."); - exit(1); - } - strcpy(testprogdir, progname); - while (*p != '\0') { - /* Support \ or / dir separators for Windows compat. */ - if (*p == '/' || *p == '\\') - { - progname = p + 1; - i = j; - } - ++p; - j++; - } - testprogdir[i] = '\0'; -#if defined(_WIN32) && !defined(__CYGWIN__) - if (testprogdir[0] != '/' && testprogdir[0] != '\\' && - !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') || - (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) && - testprogdir[1] == ':' && - (testprogdir[2] == '/' || testprogdir[2] == '\\'))) -#else - if (testprogdir[0] != '/') -#endif - { - /* Fixup path for relative directories. */ - if ((testprogdir = (char *)realloc(testprogdir, - strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL) - { - fprintf(stderr, "ERROR: Out of memory."); - exit(1); - } - memmove(testprogdir + strlen(pwd) + 1, testprogdir, - strlen(testprogdir) + 1); - memcpy(testprogdir, pwd, strlen(pwd)); - testprogdir[strlen(pwd)] = '/'; - } - -#ifdef PROGRAM - /* Get the target program from environment, if available. */ - testprogfile = getenv(ENVBASE); -#endif - - if (getenv("TMPDIR") != NULL) - tmp = getenv("TMPDIR"); - else if (getenv("TMP") != NULL) - tmp = getenv("TMP"); - else if (getenv("TEMP") != NULL) - tmp = getenv("TEMP"); - else if (getenv("TEMPDIR") != NULL) - tmp = getenv("TEMPDIR"); - else - tmp = "/tmp"; - - /* Allow -d to be controlled through the environment. */ - if (getenv(ENVBASE "_DEBUG") != NULL) - dump_on_failure = 1; - - /* Allow -v to be controlled through the environment. */ - if (getenv("_VERBOSITY_LEVEL") != NULL) - { - vlevel = getenv("_VERBOSITY_LEVEL"); - verbosity = atoi(vlevel); - if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL) - { - /* Unsupported verbosity levels are silently ignored */ - vlevel = NULL; - verbosity = VERBOSITY_PASSFAIL; - } - } - - /* Get the directory holding test files from environment. */ - refdir = getenv(ENVBASE "_TEST_FILES"); - - /* - * Parse options, without using getopt(), which isn't available - * on all platforms. - */ - ++argv; /* Skip program name */ - while (*argv != NULL) { - if (**argv != '-') - break; - p = *argv++; - ++p; /* Skip '-' */ - while (*p != '\0') { - option = *p++; - option_arg = NULL; - /* If 'opt' takes an argument, parse that. */ - if (option == 'p' || option == 'r') { - if (*p != '\0') - option_arg = p; - else if (*argv == NULL) { - fprintf(stderr, - "Option -%c requires argument.\n", - option); - usage(progname); - } else - option_arg = *argv++; - p = ""; /* End of this option word. */ - } - - /* Now, handle the option. */ - switch (option) { - case 'd': - dump_on_failure = 1; - break; - case 'k': - keep_temp_files = 1; - break; - case 'p': -#ifdef PROGRAM - testprogfile = option_arg; -#else - fprintf(stderr, "-p option not permitted\n"); - usage(progname); -#endif - break; - case 'q': - if (!vlevel) - verbosity--; - break; - case 'r': - refdir = option_arg; - break; - case 'u': - until_failure++; - break; - case 'v': - if (!vlevel) - verbosity++; - break; - default: - fprintf(stderr, "Unrecognized option '%c'\n", - option); - usage(progname); - } - } - } - - /* - * Sanity-check that our options make sense. - */ -#ifdef PROGRAM - if (testprogfile == NULL) - { - if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 + - strlen(PROGRAM) + 1)) == NULL) - { - fprintf(stderr, "ERROR: Out of memory."); - exit(1); - } - strcpy(tmp2, testprogdir); - strcat(tmp2, "/"); - strcat(tmp2, PROGRAM); - testprogfile = tmp2; - } - - { - char *testprg; -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Command.com sometimes rejects '/' separators. */ - testprg = strdup(testprogfile); - for (i = 0; testprg[i] != '\0'; i++) { - if (testprg[i] == '/') - testprg[i] = '\\'; - } - testprogfile = testprg; -#endif - /* Quote the name that gets put into shell command lines. */ - testprg = malloc(strlen(testprogfile) + 3); - strcpy(testprg, "\""); - strcat(testprg, testprogfile); - strcat(testprg, "\""); - testprog = testprg; - } -#endif - -#if !defined(_WIN32) && defined(SIGPIPE) - { /* Ignore SIGPIPE signals */ - struct sigaction sa; - sa.sa_handler = SIG_IGN; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGPIPE, &sa, NULL); - } -#endif - - /* - * Create a temp directory for the following tests. - * Include the time the tests started as part of the name, - * to make it easier to track the results of multiple tests. - */ - now = time(NULL); - for (i = 0; ; i++) { - strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp), - "%Y-%m-%dT%H.%M.%S", - localtime(&now)); - sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname, - tmpdir_timestamp, i); - if (assertMakeDir(tmpdir,0755)) - break; - if (i >= 999) { - fprintf(stderr, - "ERROR: Unable to create temp directory %s\n", - tmpdir); - exit(1); - } - } - - /* - * If the user didn't specify a directory for locating - * reference files, try to find the reference files in - * the "usual places." - */ - refdir = refdir_alloc = get_refdir(refdir); - - /* - * Banner with basic information. - */ - printf("\n"); - printf("If tests fail or crash, details will be in:\n"); - printf(" %s\n", tmpdir); - printf("\n"); - if (verbosity > VERBOSITY_SUMMARY_ONLY) { - printf("Reference files will be read from: %s\n", refdir); -#ifdef PROGRAM - printf("Running tests on: %s\n", testprog); -#endif - printf("Exercising: "); - fflush(stdout); - printf("%s\n", EXTRA_VERSION); - } else { - printf("Running "); - fflush(stdout); - } - - /* - * Run some or all of the individual tests. - */ - saved_argv = argv; - do { - argv = saved_argv; - do { - int test_num; - - test_num = get_test_set(test_set, limit, *argv, tests); - if (test_num < 0) { - printf("*** INVALID Test %s\n", *argv); - free(refdir_alloc); - free(testprogdir); - usage(progname); - return (1); - } - for (i = 0; i < test_num; i++) { - tests_run++; - if (test_run(test_set[i], tmpdir)) { - tests_failed++; - if (until_failure) - goto finish; - } - } - if (*argv != NULL) - argv++; - } while (*argv != NULL); - } while (until_failure); - -finish: - /* Must be freed after all tests run */ - free(tmp2); - free(testprogdir); - free(pwd); - - /* - * Report summary statistics. - */ - if (verbosity > VERBOSITY_SUMMARY_ONLY) { - printf("\n"); - printf("Totals:\n"); - printf(" Tests run: %8d\n", tests_run); - printf(" Tests failed: %8d\n", tests_failed); - printf(" Assertions checked:%8d\n", assertions); - printf(" Assertions failed: %8d\n", failures); - printf(" Skips reported: %8d\n", skips); - } - if (failures) { - printf("\n"); - printf("Failing tests:\n"); - for (i = 0; i < limit; ++i) { - if (tests[i].failures) - printf(" %d: %s (%d failures)\n", i, - tests[i].name, tests[i].failures); - } - printf("\n"); - printf("Details for failing tests: %s\n", tmpdir); - printf("\n"); - } else { - if (verbosity == VERBOSITY_SUMMARY_ONLY) - printf("\n"); - printf("%d tests passed, no failures\n", tests_run); - } - - free(refdir_alloc); - - /* If the final tmpdir is empty, we can remove it. */ - /* This should be the usual case when all tests succeed. */ - assertChdir(".."); - rmdir(tmpdir); - - return (tests_failed ? 1 : 0); -} diff --git a/cat/test/test.h b/cat/test/test.h index 3a23a05a..350bcad6 100644 --- a/cat/test/test.h +++ b/cat/test/test.h @@ -22,333 +22,19 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/usr.bin/tar/test/test.h,v 1.4 2008/08/21 07:04:57 kientzle Exp $ + * $FreeBSD$ */ /* Every test program should #include "test.h" as the first thing. */ -/* - * The goal of this file (and the matching test.c) is to - * simplify the very repetitive test-*.c test programs. - */ -#if defined(HAVE_CONFIG_H) -/* Most POSIX platforms use the 'configure' script to build config.h */ -#include "config.h" -#elif defined(__FreeBSD__) -/* Building as part of FreeBSD system requires a pre-built config.h. */ -#include "config_freebsd.h" -#elif defined(_WIN32) && !defined(__CYGWIN__) -/* Win32 can't run the 'configure' script. */ -#include "config_windows.h" -#else -/* Warn if the library hasn't been (automatically or manually) configured. */ -#error Oops: No config.h and no pre-built configuration in test.h. -#endif - -#include <sys/types.h> /* Windows requires this before sys/stat.h */ -#include <sys/stat.h> - -#if HAVE_DIRENT_H -#include <dirent.h> -#endif -#ifdef HAVE_DIRECT_H -#include <direct.h> -#define dirent direct -#endif -#include <errno.h> -#include <fcntl.h> -#ifdef HAVE_IO_H -#include <io.h> -#endif -#ifdef HAVE_STDINT_H -#include <stdint.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <time.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <wchar.h> -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif - -/* - * System-specific tweaks. We really want to minimize these - * as much as possible, since they make it harder to understand - * the mainline code. - */ - -/* Windows (including Visual Studio and MinGW but not Cygwin) */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#if !defined(__BORLANDC__) -#undef chdir -#define chdir _chdir -#define strdup _strdup -#endif -#endif - -/* Visual Studio */ -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf sprintf_s -#endif - -#if defined(__BORLANDC__) -#pragma warn -8068 /* Constant out of range in comparison. */ -#endif - -/* Haiku OS and QNX */ -#if defined(__HAIKU__) || defined(__QNXNTO__) -/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */ -#include <stdint.h> -#endif - -/* Get a real definition for __FBSDID if we can */ -#if HAVE_SYS_CDEFS_H -#include <sys/cdefs.h> -#endif - -/* If not, define it so as to avoid dangling semicolons. */ -#ifndef __FBSDID -#define __FBSDID(a) struct _undefined_hack -#endif - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -/* - * Redefine DEFINE_TEST for use in defining the test functions. - */ -#undef DEFINE_TEST -#define DEFINE_TEST(name) void name(void); void name(void) - -/* An implementation of the standard assert() macro */ -#define assert(e) assertion_assert(__FILE__, __LINE__, (e), #e, NULL) -/* chdir() and error if it fails */ -#define assertChdir(path) \ - assertion_chdir(__FILE__, __LINE__, path) -/* Assert two integers are the same. Reports value of each one if not. */ -#define assertEqualInt(v1,v2) \ - assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) -/* Assert two strings are the same. Reports value of each one if not. */ -#define assertEqualString(v1,v2) \ - assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0) -#define assertEqualUTF8String(v1,v2) \ - assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1) -/* As above, but v1 and v2 are wchar_t * */ -#define assertEqualWString(v1,v2) \ - assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) -/* As above, but raw blocks of bytes. */ -#define assertEqualMem(v1, v2, l) \ - assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL) -/* Assert that memory is full of a specified byte */ -#define assertMemoryFilledWith(v1, l, b) \ - assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL) -/* Assert two files are the same. */ -#define assertEqualFile(f1, f2) \ - assertion_equal_file(__FILE__, __LINE__, (f1), (f2)) -/* Assert that a file is empty. */ -#define assertEmptyFile(pathname) \ - assertion_empty_file(__FILE__, __LINE__, (pathname)) -/* Assert that a file is not empty. */ -#define assertNonEmptyFile(pathname) \ - assertion_non_empty_file(__FILE__, __LINE__, (pathname)) -#define assertFileAtime(pathname, sec, nsec) \ - assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileAtimeRecent(pathname) \ - assertion_file_atime_recent(__FILE__, __LINE__, pathname) -#define assertFileBirthtime(pathname, sec, nsec) \ - assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileBirthtimeRecent(pathname) \ - assertion_file_birthtime_recent(__FILE__, __LINE__, pathname) -/* Assert that a file exists; supports printf-style arguments. */ -#define assertFileExists(pathname) \ - assertion_file_exists(__FILE__, __LINE__, pathname) -/* Assert that a file exists. */ -#define assertFileNotExists(pathname) \ - assertion_file_not_exists(__FILE__, __LINE__, pathname) -/* Assert that file contents match a string. */ -#define assertFileContents(data, data_size, pathname) \ - assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname) -/* Verify that a file does not contain invalid strings */ -#define assertFileContainsNoInvalidStrings(pathname, strings) \ - assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings) -#define assertFileMtime(pathname, sec, nsec) \ - assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileMtimeRecent(pathname) \ - assertion_file_mtime_recent(__FILE__, __LINE__, pathname) -#define assertFileNLinks(pathname, nlinks) \ - assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks) -#define assertFileSize(pathname, size) \ - assertion_file_size(__FILE__, __LINE__, pathname, size) -#define assertFileMode(pathname, mode) \ - assertion_file_mode(__FILE__, __LINE__, pathname, mode) -#define assertTextFileContents(text, pathname) \ - assertion_text_file_contents(__FILE__, __LINE__, text, pathname) -#define assertFileContainsLinesAnyOrder(pathname, lines) \ - assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines) -#define assertIsDir(pathname, mode) \ - assertion_is_dir(__FILE__, __LINE__, pathname, mode) -#define assertIsHardlink(path1, path2) \ - assertion_is_hardlink(__FILE__, __LINE__, path1, path2) -#define assertIsNotHardlink(path1, path2) \ - assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2) -#define assertIsReg(pathname, mode) \ - assertion_is_reg(__FILE__, __LINE__, pathname, mode) -#define assertIsSymlink(pathname, contents) \ - assertion_is_symlink(__FILE__, __LINE__, pathname, contents) -/* Create a directory, report error if it fails. */ -#define assertMakeDir(dirname, mode) \ - assertion_make_dir(__FILE__, __LINE__, dirname, mode) -#define assertMakeFile(path, mode, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents) -#define assertMakeBinFile(path, mode, csize, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents) -#define assertMakeHardlink(newfile, oldfile) \ - assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) -#define assertMakeSymlink(newfile, linkto) \ - assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) -#define assertNodump(path) \ - assertion_nodump(__FILE__, __LINE__, path) -#define assertUmask(mask) \ - assertion_umask(__FILE__, __LINE__, mask) -#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \ - assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec) - -/* - * This would be simple with C99 variadic macros, but I don't want to - * require that. Instead, I insert a function call before each - * skipping() call to pass the file and line information down. Crude, - * but effective. - */ -#define skipping \ - skipping_setup(__FILE__, __LINE__);test_skipping - -/* Function declarations. These are defined in test_utility.c. */ -void failure(const char *fmt, ...); -int assertion_assert(const char *, int, int, const char *, void *); -int assertion_chdir(const char *, int, const char *); -int assertion_empty_file(const char *, int, const char *); -int assertion_equal_file(const char *, int, const char *, const char *); -int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *); -int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *); -int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *); -int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int); -int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); -int assertion_file_atime(const char *, int, const char *, long, long); -int assertion_file_atime_recent(const char *, int, const char *); -int assertion_file_birthtime(const char *, int, const char *, long, long); -int assertion_file_birthtime_recent(const char *, int, const char *); -int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **); -int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **); -int assertion_file_contents(const char *, int, const void *, int, const char *); -int assertion_file_exists(const char *, int, const char *); -int assertion_file_mode(const char *, int, const char *, int); -int assertion_file_mtime(const char *, int, const char *, long, long); -int assertion_file_mtime_recent(const char *, int, const char *); -int assertion_file_nlinks(const char *, int, const char *, int); -int assertion_file_not_exists(const char *, int, const char *); -int assertion_file_size(const char *, int, const char *, long); -int assertion_is_dir(const char *, int, const char *, int); -int assertion_is_hardlink(const char *, int, const char *, const char *); -int assertion_is_not_hardlink(const char *, int, const char *, const char *); -int assertion_is_reg(const char *, int, const char *, int); -int assertion_is_symlink(const char *, int, const char *, const char *); -int assertion_make_dir(const char *, int, const char *, int); -int assertion_make_file(const char *, int, const char *, int, int, const void *); -int assertion_make_hardlink(const char *, int, const char *newpath, const char *); -int assertion_make_symlink(const char *, int, const char *newpath, const char *); -int assertion_nodump(const char *, int, const char *); -int assertion_non_empty_file(const char *, int, const char *); -int assertion_text_file_contents(const char *, int, const char *buff, const char *f); -int assertion_umask(const char *, int, int); -int assertion_utimes(const char *, int, const char *, long, long, long, long ); - -void skipping_setup(const char *, int); -void test_skipping(const char *fmt, ...); - -/* Like sprintf, then system() */ -int systemf(const char * fmt, ...); - -/* Delay until time() returns a value after this. */ -void sleepUntilAfter(time_t); - -/* Return true if this platform can create symlinks. */ -int canSymlink(void); - -/* Return true if this platform can run the "bzip2" program. */ -int canBzip2(void); - -/* Return true if this platform can run the "grzip" program. */ -int canGrzip(void); - -/* Return true if this platform can run the "gzip" program. */ -int canGzip(void); - -/* Return true if this platform can run the specified command. */ -int canRunCommand(const char *); - -/* Return true if this platform can run the "lrzip" program. */ -int canLrzip(void); - -/* Return true if this platform can run the "lz4" program. */ -int canLz4(void); - -/* Return true if this platform can run the "lzip" program. */ -int canLzip(void); - -/* Return true if this platform can run the "lzma" program. */ -int canLzma(void); - -/* Return true if this platform can run the "lzop" program. */ -int canLzop(void); - -/* Return true if this platform can run the "xz" program. */ -int canXz(void); - -/* Return true if this filesystem can handle nodump flags. */ -int canNodump(void); - -/* Return true if the file has large i-node number(>0xffffffff). */ -int is_LargeInode(const char *); - -/* Suck file into string allocated via malloc(). Call free() when done. */ -/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */ -char *slurpfile(size_t *, const char *fmt, ...); - -/* Dump block of bytes to a file. */ -void dumpfile(const char *filename, void *, size_t); - -/* Extracts named reference file to the current directory. */ -void extract_reference_file(const char *); -/* Copies named reference file to the current directory. */ -void copy_reference_file(const char *); - -/* Extracts a list of files to the current directory. - * List must be NULL terminated. - */ -void extract_reference_files(const char **); - -/* Subtract umask from mode */ -mode_t umasked(mode_t expected_mode); - -/* Path to working directory for current test */ -extern const char *testworkdir; - -/* - * Special interfaces for program test harness. - */ - -/* Pathname of exe to be tested. */ -extern const char *testprogfile; -/* Name of exe to use in printf-formatted command strings. */ -/* On Windows, this includes leading/trailing quotes. */ -extern const char *testprog; - -#ifdef USE_DMALLOC -#include <dmalloc.h> -#endif +#define KNOWNREF "test_expand.Z.uu" +#define ENVBASE "BSDCAT" /* Prefix for environment variables. */ +#define PROGRAM "bsdcat" /* Name of program being tested. */ +#define PROGRAM_ALIAS "cat" /* Generic alias for program */ +#undef LIBRARY /* Not testing a library. */ +#undef EXTRA_DUMP /* How to dump extra data */ +#undef EXTRA_ERRNO /* How to dump errno */ +/* How to generate extra version info. */ +#define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") + +#include "test_common.h" diff --git a/cat/test/test_version.c b/cat/test/test_version.c index f582a13f..51a4fd4d 100644 --- a/cat/test/test_version.c +++ b/cat/test/test_version.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2003-2017 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,8 +28,6 @@ * Test that --version option works and generates reasonable output. */ -#include "lib/version.h" - DEFINE_TEST(test_version) { assertVersion(testprog, "bsdcat"); diff --git a/cpio/test/CMakeLists.txt b/cpio/test/CMakeLists.txt index c99ef65a..ec9509be 100644 --- a/cpio/test/CMakeLists.txt +++ b/cpio/test/CMakeLists.txt @@ -8,8 +8,7 @@ IF(ENABLE_CPIO AND ENABLE_TEST) ../cmdline.c ../../libarchive_fe/err.c ../../test_utils/test_utils.c - ../../test_utils/lib/version.c - main.c + ../../test_utils/test_main.c test.h test_0.c test_basic.c @@ -88,6 +87,7 @@ IF(ENABLE_CPIO AND ENABLE_TEST) INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cpio/test) # Experimental new test handling ADD_CUSTOM_TARGET(run_bsdcpio_test diff --git a/cpio/test/main.c b/cpio/test/main.c deleted file mode 100644 index 34282f3f..00000000 --- a/cpio/test/main.c +++ /dev/null @@ -1,3073 +0,0 @@ -/* - * Copyright (c) 2003-2009 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "test.h" -#include "test_utils.h" -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#include <errno.h> -#ifdef HAVE_ICONV_H -#include <iconv.h> -#endif -/* - * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. - * As the include guards don't agree, the order of include is important. - */ -#ifdef HAVE_LINUX_EXT2_FS_H -#include <linux/ext2_fs.h> /* for Linux file flags */ -#endif -#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) -#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ -#endif -#include <limits.h> -#include <locale.h> -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#include <stdarg.h> -#include <time.h> - -/* - * This same file is used pretty much verbatim for all test harnesses. - * - * The next few lines are the only differences. - * TODO: Move this into a separate configuration header, have all test - * suites share one copy of this file. - */ -__FBSDID("$FreeBSD: src/usr.bin/cpio/test/main.c,v 1.3 2008/08/24 04:58:22 kientzle Exp $"); -#define KNOWNREF "test_option_f.cpio.uu" -#define ENVBASE "BSDCPIO" /* Prefix for environment variables. */ -#define PROGRAM "bsdcpio" /* Name of program being tested. */ -#define PROGRAM_ALIAS "cpio" /* Generic alias for program */ -#undef LIBRARY /* Not testing a library. */ -#undef EXTRA_DUMP /* How to dump extra data */ -#undef EXTRA_ERRNO /* How to dump errno */ -/* How to generate extra version info. */ -#define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") - -/* - * - * Windows support routines - * - * Note: Configuration is a tricky issue. Using HAVE_* feature macros - * in the test harness is dangerous because they cover up - * configuration errors. The classic example of this is omitting a - * configure check. If libarchive and libarchive_test both look for - * the same feature macro, such errors are hard to detect. Platform - * macros (e.g., _WIN32 or __GNUC__) are a little better, but can - * easily lead to very messy code. It's best to limit yourself - * to only the most generic programming techniques in the test harness - * and thus avoid conditionals altogether. Where that's not possible, - * try to minimize conditionals by grouping platform-specific tests in - * one place (e.g., test_acl_freebsd) or by adding new assert() - * functions (e.g., assertMakeHardlink()) to cover up platform - * differences. Platform-specific coding in libarchive_test is often - * a symptom that some capability is missing from libarchive itself. - */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#include <io.h> -#include <direct.h> -#include <windows.h> -#ifndef F_OK -#define F_OK (0) -#endif -#ifndef S_ISDIR -#define S_ISDIR(m) ((m) & _S_IFDIR) -#endif -#ifndef S_ISREG -#define S_ISREG(m) ((m) & _S_IFREG) -#endif -#if !defined(__BORLANDC__) -#define access _access -#undef chdir -#define chdir _chdir -#endif -#ifndef fileno -#define fileno _fileno -#endif -/*#define fstat _fstat64*/ -#if !defined(__BORLANDC__) -#define getcwd _getcwd -#endif -#define lstat stat -/*#define lstat _stat64*/ -/*#define stat _stat64*/ -#define rmdir _rmdir -#if !defined(__BORLANDC__) -#define strdup _strdup -#define umask _umask -#endif -#define int64_t __int64 -#endif - -#if defined(HAVE__CrtSetReportMode) -# include <crtdbg.h> -#endif - -mode_t umasked(mode_t expected_mode) -{ - mode_t mode = umask(0); - umask(mode); - return expected_mode & ~mode; -} - -/* Path to working directory for current test */ -const char *testworkdir; -#ifdef PROGRAM -/* Pathname of exe to be tested. */ -const char *testprogfile; -/* Name of exe to use in printf-formatted command strings. */ -/* On Windows, this includes leading/trailing quotes. */ -const char *testprog; -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) -static void *GetFunctionKernel32(const char *); -static int my_CreateSymbolicLinkA(const char *, const char *, int); -static int my_CreateHardLinkA(const char *, const char *); -static int my_GetFileInformationByName(const char *, - BY_HANDLE_FILE_INFORMATION *); - -static void * -GetFunctionKernel32(const char *name) -{ - static HINSTANCE lib; - static int set; - if (!set) { - set = 1; - lib = LoadLibrary("kernel32.dll"); - } - if (lib == NULL) { - fprintf(stderr, "Can't load kernel32.dll?!\n"); - exit(1); - } - return (void *)GetProcAddress(lib, name); -} - -static int -my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags) -{ - static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD); - static int set; - if (!set) { - set = 1; - f = GetFunctionKernel32("CreateSymbolicLinkA"); - } - return f == NULL ? 0 : (*f)(linkname, target, flags); -} - -static int -my_CreateHardLinkA(const char *linkname, const char *target) -{ - static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); - static int set; - if (!set) { - set = 1; - f = GetFunctionKernel32("CreateHardLinkA"); - } - return f == NULL ? 0 : (*f)(linkname, target, NULL); -} - -static int -my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) -{ - HANDLE h; - int r; - - memset(bhfi, 0, sizeof(*bhfi)); - h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) - return (0); - r = GetFileInformationByHandle(h, bhfi); - CloseHandle(h); - return (r); -} -#endif - -#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__) -static void -invalid_parameter_handler(const wchar_t * expression, - const wchar_t * function, const wchar_t * file, - unsigned int line, uintptr_t pReserved) -{ - /* nop */ -} -#endif - -/* - * - * OPTIONS FLAGS - * - */ - -/* Enable core dump on failure. */ -static int dump_on_failure = 0; -/* Default is to remove temp dirs and log data for successful tests. */ -static int keep_temp_files = 0; -/* Default is to run the specified tests once and report errors. */ -static int until_failure = 0; -/* Default is to just report pass/fail for each test. */ -static int verbosity = 0; -#define VERBOSITY_SUMMARY_ONLY -1 /* -q */ -#define VERBOSITY_PASSFAIL 0 /* Default */ -#define VERBOSITY_LIGHT_REPORT 1 /* -v */ -#define VERBOSITY_FULL 2 /* -vv */ -/* A few places generate even more output for verbosity > VERBOSITY_FULL, - * mostly for debugging the test harness itself. */ -/* Cumulative count of assertion failures. */ -static int failures = 0; -/* Cumulative count of reported skips. */ -static int skips = 0; -/* Cumulative count of assertions checked. */ -static int assertions = 0; - -/* Directory where uuencoded reference files can be found. */ -static const char *refdir; - -/* - * Report log information selectively to console and/or disk log. - */ -static int log_console = 0; -static FILE *logfile; -static void -vlogprintf(const char *fmt, va_list ap) -{ -#ifdef va_copy - va_list lfap; - va_copy(lfap, ap); -#endif - if (log_console) - vfprintf(stdout, fmt, ap); - if (logfile != NULL) -#ifdef va_copy - vfprintf(logfile, fmt, lfap); - va_end(lfap); -#else - vfprintf(logfile, fmt, ap); -#endif -} - -static void -logprintf(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vlogprintf(fmt, ap); - va_end(ap); -} - -/* Set up a message to display only if next assertion fails. */ -static char msgbuff[4096]; -static const char *msg, *nextmsg; -void -failure(const char *fmt, ...) -{ - va_list ap; - if (fmt == NULL) { - nextmsg = NULL; - } else { - va_start(ap, fmt); - vsprintf(msgbuff, fmt, ap); - va_end(ap); - nextmsg = msgbuff; - } -} - -/* - * Copy arguments into file-local variables. - * This was added to permit vararg assert() functions without needing - * variadic wrapper macros. Turns out that the vararg capability is almost - * never used, so almost all of the vararg assertions can be simplified - * by removing the vararg capability and reworking the wrapper macro to - * pass __FILE__, __LINE__ directly into the function instead of using - * this hook. I suspect this machinery is used so rarely that we - * would be better off just removing it entirely. That would simplify - * the code here noticeably. - */ -static const char *skipping_filename; -static int skipping_line; -void skipping_setup(const char *filename, int line) -{ - skipping_filename = filename; - skipping_line = line; -} - -/* Called at the beginning of each assert() function. */ -static void -assertion_count(const char *file, int line) -{ - (void)file; /* UNUSED */ - (void)line; /* UNUSED */ - ++assertions; - /* Proper handling of "failure()" message. */ - msg = nextmsg; - nextmsg = NULL; - /* Uncomment to print file:line after every assertion. - * Verbose, but occasionally useful in tracking down crashes. */ - /* printf("Checked %s:%d\n", file, line); */ -} - -/* - * For each test source file, we remember how many times each - * assertion was reported. Cleared before each new test, - * used by test_summarize(). - */ -static struct line { - int count; - int skip; -} failed_lines[10000]; -const char *failed_filename; - -/* Count this failure, setup up log destination and handle initial report. */ -static void -failure_start(const char *filename, int line, const char *fmt, ...) -{ - va_list ap; - - /* Record another failure for this line. */ - ++failures; - failed_filename = filename; - failed_lines[line].count++; - - /* Determine whether to log header to console. */ - switch (verbosity) { - case VERBOSITY_LIGHT_REPORT: - log_console = (failed_lines[line].count < 2); - break; - default: - log_console = (verbosity >= VERBOSITY_FULL); - } - - /* Log file:line header for this failure */ - va_start(ap, fmt); -#if _MSC_VER - logprintf("%s(%d): ", filename, line); -#else - logprintf("%s:%d: ", filename, line); -#endif - vlogprintf(fmt, ap); - va_end(ap); - logprintf("\n"); - - if (msg != NULL && msg[0] != '\0') { - logprintf(" Description: %s\n", msg); - msg = NULL; - } - - /* Determine whether to log details to console. */ - if (verbosity == VERBOSITY_LIGHT_REPORT) - log_console = 0; -} - -/* Complete reporting of failed tests. */ -/* - * The 'extra' hook here is used by libarchive to include libarchive - * error messages with assertion failures. It could also be used - * to add strerror() output, for example. Just define the EXTRA_DUMP() - * macro appropriately. - */ -static void -failure_finish(void *extra) -{ - (void)extra; /* UNUSED (maybe) */ -#ifdef EXTRA_DUMP - if (extra != NULL) { - logprintf(" errno: %d\n", EXTRA_ERRNO(extra)); - logprintf(" detail: %s\n", EXTRA_DUMP(extra)); - } -#endif - - if (dump_on_failure) { - fprintf(stderr, - " *** forcing core dump so failure can be debugged ***\n"); - abort(); - } -} - -/* Inform user that we're skipping some checks. */ -void -test_skipping(const char *fmt, ...) -{ - char buff[1024]; - va_list ap; - - va_start(ap, fmt); - vsprintf(buff, fmt, ap); - va_end(ap); - /* Use failure() message if set. */ - msg = nextmsg; - nextmsg = NULL; - /* failure_start() isn't quite right, but is awfully convenient. */ - failure_start(skipping_filename, skipping_line, "SKIPPING: %s", buff); - --failures; /* Undo failures++ in failure_start() */ - /* Don't failure_finish() here. */ - /* Mark as skip, so doesn't count as failed test. */ - failed_lines[skipping_line].skip = 1; - ++skips; -} - -/* - * - * ASSERTIONS - * - */ - -/* Generic assert() just displays the failed condition. */ -int -assertion_assert(const char *file, int line, int value, - const char *condition, void *extra) -{ - assertion_count(file, line); - if (!value) { - failure_start(file, line, "Assertion failed: %s", condition); - failure_finish(extra); - } - return (value); -} - -/* chdir() and report any errors */ -int -assertion_chdir(const char *file, int line, const char *pathname) -{ - assertion_count(file, line); - if (chdir(pathname) == 0) - return (1); - failure_start(file, line, "chdir(\"%s\")", pathname); - failure_finish(NULL); - return (0); - -} - -/* Verify two integers are equal. */ -int -assertion_equal_int(const char *file, int line, - long long v1, const char *e1, long long v2, const char *e2, void *extra) -{ - assertion_count(file, line); - if (v1 == v2) - return (1); - failure_start(file, line, "%s != %s", e1, e2); - logprintf(" %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1); - logprintf(" %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2); - failure_finish(extra); - return (0); -} - -/* - * Utility to convert a single UTF-8 sequence. - */ -static int -_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) -{ - static const char utf8_count[256] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */ - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */ - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ - }; - int ch; - int cnt; - uint32_t wc; - - *pwc = 0; - - /* Sanity check. */ - if (n == 0) - return (0); - /* - * Decode 1-4 bytes depending on the value of the first byte. - */ - ch = (unsigned char)*s; - if (ch == 0) - return (0); /* Standard: return 0 for end-of-string. */ - cnt = utf8_count[ch]; - - /* Invalid sequence or there are not plenty bytes. */ - if (n < (size_t)cnt) - return (-1); - - /* Make a Unicode code point from a single UTF-8 sequence. */ - switch (cnt) { - case 1: /* 1 byte sequence. */ - *pwc = ch & 0x7f; - return (cnt); - case 2: /* 2 bytes sequence. */ - if ((s[1] & 0xc0) != 0x80) return (-1); - *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f); - return (cnt); - case 3: /* 3 bytes sequence. */ - if ((s[1] & 0xc0) != 0x80) return (-1); - if ((s[2] & 0xc0) != 0x80) return (-1); - wc = ((ch & 0x0f) << 12) - | ((s[1] & 0x3f) << 6) - | (s[2] & 0x3f); - if (wc < 0x800) - return (-1);/* Overlong sequence. */ - break; - case 4: /* 4 bytes sequence. */ - if (n < 4) - return (-1); - if ((s[1] & 0xc0) != 0x80) return (-1); - if ((s[2] & 0xc0) != 0x80) return (-1); - if ((s[3] & 0xc0) != 0x80) return (-1); - wc = ((ch & 0x07) << 18) - | ((s[1] & 0x3f) << 12) - | ((s[2] & 0x3f) << 6) - | (s[3] & 0x3f); - if (wc < 0x10000) - return (-1);/* Overlong sequence. */ - break; - default: - return (-1); - } - - /* The code point larger than 0x10FFFF is not legal - * Unicode values. */ - if (wc > 0x10FFFF) - return (-1); - /* Correctly gets a Unicode, returns used bytes. */ - *pwc = wc; - return (cnt); -} - -static void strdump(const char *e, const char *p, int ewidth, int utf8) -{ - const char *q = p; - - logprintf(" %*s = ", ewidth, e); - if (p == NULL) { - logprintf("NULL\n"); - return; - } - logprintf("\""); - while (*p != '\0') { - unsigned int c = 0xff & *p++; - switch (c) { - case '\a': logprintf("\\a"); break; - case '\b': logprintf("\\b"); break; - case '\n': logprintf("\\n"); break; - case '\r': logprintf("\\r"); break; - default: - if (c >= 32 && c < 127) - logprintf("%c", c); - else - logprintf("\\x%02X", c); - } - } - logprintf("\""); - logprintf(" (length %d)", q == NULL ? -1 : (int)strlen(q)); - - /* - * If the current string is UTF-8, dump its code points. - */ - if (utf8) { - size_t len; - uint32_t uc; - int n; - int cnt = 0; - - p = q; - len = strlen(p); - logprintf(" ["); - while ((n = _utf8_to_unicode(&uc, p, len)) > 0) { - if (p != q) - logprintf(" "); - logprintf("%04X", uc); - p += n; - len -= n; - cnt++; - } - logprintf("]"); - logprintf(" (count %d", cnt); - if (n < 0) { - logprintf(",unknown %d bytes", len); - } - logprintf(")"); - - } - logprintf("\n"); -} - -/* Verify two strings are equal, dump them if not. */ -int -assertion_equal_string(const char *file, int line, - const char *v1, const char *e1, - const char *v2, const char *e2, - void *extra, int utf8) -{ - int l1, l2; - - assertion_count(file, line); - if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0)) - return (1); - failure_start(file, line, "%s != %s", e1, e2); - l1 = (int)strlen(e1); - l2 = (int)strlen(e2); - if (l1 < l2) - l1 = l2; - strdump(e1, v1, l1, utf8); - strdump(e2, v2, l1, utf8); - failure_finish(extra); - return (0); -} - -static void -wcsdump(const char *e, const wchar_t *w) -{ - logprintf(" %s = ", e); - if (w == NULL) { - logprintf("(null)"); - return; - } - logprintf("\""); - while (*w != L'\0') { - unsigned int c = *w++; - if (c >= 32 && c < 127) - logprintf("%c", c); - else if (c < 256) - logprintf("\\x%02X", c); - else if (c < 0x10000) - logprintf("\\u%04X", c); - else - logprintf("\\U%08X", c); - } - logprintf("\"\n"); -} - -#ifndef HAVE_WCSCMP -static int -wcscmp(const wchar_t *s1, const wchar_t *s2) -{ - - while (*s1 == *s2++) { - if (*s1++ == L'\0') - return 0; - } - if (*s1 > *--s2) - return 1; - else - return -1; -} -#endif - -/* Verify that two wide strings are equal, dump them if not. */ -int -assertion_equal_wstring(const char *file, int line, - const wchar_t *v1, const char *e1, - const wchar_t *v2, const char *e2, - void *extra) -{ - assertion_count(file, line); - if (v1 == v2) - return (1); - if (v1 != NULL && v2 != NULL && wcscmp(v1, v2) == 0) - return (1); - failure_start(file, line, "%s != %s", e1, e2); - wcsdump(e1, v1); - wcsdump(e2, v2); - failure_finish(extra); - return (0); -} - -/* - * Pretty standard hexdump routine. As a bonus, if ref != NULL, then - * any bytes in p that differ from ref will be highlighted with '_' - * before and after the hex value. - */ -static void -hexdump(const char *p, const char *ref, size_t l, size_t offset) -{ - size_t i, j; - char sep; - - if (p == NULL) { - logprintf("(null)\n"); - return; - } - for(i=0; i < l; i+=16) { - logprintf("%04x", (unsigned)(i + offset)); - sep = ' '; - for (j = 0; j < 16 && i + j < l; j++) { - if (ref != NULL && p[i + j] != ref[i + j]) - sep = '_'; - logprintf("%c%02x", sep, 0xff & (int)p[i+j]); - if (ref != NULL && p[i + j] == ref[i + j]) - sep = ' '; - } - for (; j < 16; j++) { - logprintf("%c ", sep); - sep = ' '; - } - logprintf("%c", sep); - for (j=0; j < 16 && i + j < l; j++) { - int c = p[i + j]; - if (c >= ' ' && c <= 126) - logprintf("%c", c); - else - logprintf("."); - } - logprintf("\n"); - } -} - -/* Verify that two blocks of memory are the same, display the first - * block of differences if they're not. */ -int -assertion_equal_mem(const char *file, int line, - const void *_v1, const char *e1, - const void *_v2, const char *e2, - size_t l, const char *ld, void *extra) -{ - const char *v1 = (const char *)_v1; - const char *v2 = (const char *)_v2; - size_t offset; - - assertion_count(file, line); - if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0)) - return (1); - if (v1 == NULL || v2 == NULL) - return (0); - - failure_start(file, line, "%s != %s", e1, e2); - logprintf(" size %s = %d\n", ld, (int)l); - /* Dump 48 bytes (3 lines) so that the first difference is - * in the second line. */ - offset = 0; - while (l > 64 && memcmp(v1, v2, 32) == 0) { - /* Two lines agree, so step forward one line. */ - v1 += 16; - v2 += 16; - l -= 16; - offset += 16; - } - logprintf(" Dump of %s\n", e1); - hexdump(v1, v2, l < 128 ? l : 128, offset); - logprintf(" Dump of %s\n", e2); - hexdump(v2, v1, l < 128 ? l : 128, offset); - logprintf("\n"); - failure_finish(extra); - return (0); -} - -/* Verify that a block of memory is filled with the specified byte. */ -int -assertion_memory_filled_with(const char *file, int line, - const void *_v1, const char *vd, - size_t l, const char *ld, - char b, const char *bd, void *extra) -{ - const char *v1 = (const char *)_v1; - size_t c = 0; - size_t i; - (void)ld; /* UNUSED */ - - assertion_count(file, line); - - for (i = 0; i < l; ++i) { - if (v1[i] == b) { - ++c; - } - } - if (c == l) - return (1); - - failure_start(file, line, "%s (size %d) not filled with %s", vd, (int)l, bd); - logprintf(" Only %d bytes were correct\n", (int)c); - failure_finish(extra); - return (0); -} - -/* Verify that the named file exists and is empty. */ -int -assertion_empty_file(const char *filename, int line, const char *f1) -{ - char buff[1024]; - struct stat st; - ssize_t s; - FILE *f; - - assertion_count(filename, line); - - if (stat(f1, &st) != 0) { - failure_start(filename, line, "Stat failed: %s", f1); - failure_finish(NULL); - return (0); - } - if (st.st_size == 0) - return (1); - - failure_start(filename, line, "File should be empty: %s", f1); - logprintf(" File size: %d\n", (int)st.st_size); - logprintf(" Contents:\n"); - f = fopen(f1, "rb"); - if (f == NULL) { - logprintf(" Unable to open %s\n", f1); - } else { - s = ((off_t)sizeof(buff) < st.st_size) ? - (ssize_t)sizeof(buff) : (ssize_t)st.st_size; - s = fread(buff, 1, s, f); - hexdump(buff, NULL, s, 0); - fclose(f); - } - failure_finish(NULL); - return (0); -} - -/* Verify that the named file exists and is not empty. */ -int -assertion_non_empty_file(const char *filename, int line, const char *f1) -{ - struct stat st; - - assertion_count(filename, line); - - if (stat(f1, &st) != 0) { - failure_start(filename, line, "Stat failed: %s", f1); - failure_finish(NULL); - return (0); - } - if (st.st_size == 0) { - failure_start(filename, line, "File empty: %s", f1); - failure_finish(NULL); - return (0); - } - return (1); -} - -/* Verify that two files have the same contents. */ -/* TODO: hexdump the first bytes that actually differ. */ -int -assertion_equal_file(const char *filename, int line, const char *fn1, const char *fn2) -{ - char buff1[1024]; - char buff2[1024]; - FILE *f1, *f2; - int n1, n2; - - assertion_count(filename, line); - - f1 = fopen(fn1, "rb"); - f2 = fopen(fn2, "rb"); - if (f1 == NULL || f2 == NULL) { - if (f1) fclose(f1); - if (f2) fclose(f2); - return (0); - } - for (;;) { - n1 = (int)fread(buff1, 1, sizeof(buff1), f1); - n2 = (int)fread(buff2, 1, sizeof(buff2), f2); - if (n1 != n2) - break; - if (n1 == 0 && n2 == 0) { - fclose(f1); - fclose(f2); - return (1); - } - if (memcmp(buff1, buff2, n1) != 0) - break; - } - fclose(f1); - fclose(f2); - failure_start(filename, line, "Files not identical"); - logprintf(" file1=\"%s\"\n", fn1); - logprintf(" file2=\"%s\"\n", fn2); - failure_finish(NULL); - return (0); -} - -/* Verify that the named file does exist. */ -int -assertion_file_exists(const char *filename, int line, const char *f) -{ - assertion_count(filename, line); - -#if defined(_WIN32) && !defined(__CYGWIN__) - if (!_access(f, 0)) - return (1); -#else - if (!access(f, F_OK)) - return (1); -#endif - failure_start(filename, line, "File should exist: %s", f); - failure_finish(NULL); - return (0); -} - -/* Verify that the named file doesn't exist. */ -int -assertion_file_not_exists(const char *filename, int line, const char *f) -{ - assertion_count(filename, line); - -#if defined(_WIN32) && !defined(__CYGWIN__) - if (_access(f, 0)) - return (1); -#else - if (access(f, F_OK)) - return (1); -#endif - failure_start(filename, line, "File should not exist: %s", f); - failure_finish(NULL); - return (0); -} - -/* Compare the contents of a file to a block of memory. */ -int -assertion_file_contents(const char *filename, int line, const void *buff, int s, const char *fn) -{ - char *contents; - FILE *f; - int n; - - assertion_count(filename, line); - - f = fopen(fn, "rb"); - if (f == NULL) { - failure_start(filename, line, - "File should exist: %s", fn); - failure_finish(NULL); - return (0); - } - contents = malloc(s * 2); - n = (int)fread(contents, 1, s * 2, f); - fclose(f); - if (n == s && memcmp(buff, contents, s) == 0) { - free(contents); - return (1); - } - failure_start(filename, line, "File contents don't match"); - logprintf(" file=\"%s\"\n", fn); - if (n > 0) - hexdump(contents, buff, n > 512 ? 512 : n, 0); - else { - logprintf(" File empty, contents should be:\n"); - hexdump(buff, NULL, s > 512 ? 512 : s, 0); - } - failure_finish(NULL); - free(contents); - return (0); -} - -/* Check the contents of a text file, being tolerant of line endings. */ -int -assertion_text_file_contents(const char *filename, int line, const char *buff, const char *fn) -{ - char *contents; - const char *btxt, *ftxt; - FILE *f; - int n, s; - - assertion_count(filename, line); - f = fopen(fn, "r"); - if (f == NULL) { - failure_start(filename, line, - "File doesn't exist: %s", fn); - failure_finish(NULL); - return (0); - } - s = (int)strlen(buff); - contents = malloc(s * 2 + 128); - n = (int)fread(contents, 1, s * 2 + 128 - 1, f); - if (n >= 0) - contents[n] = '\0'; - fclose(f); - /* Compare texts. */ - btxt = buff; - ftxt = (const char *)contents; - while (*btxt != '\0' && *ftxt != '\0') { - if (*btxt == *ftxt) { - ++btxt; - ++ftxt; - continue; - } - if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') { - /* Pass over different new line characters. */ - ++btxt; - ftxt += 2; - continue; - } - break; - } - if (*btxt == '\0' && *ftxt == '\0') { - free(contents); - return (1); - } - failure_start(filename, line, "Contents don't match"); - logprintf(" file=\"%s\"\n", fn); - if (n > 0) { - hexdump(contents, buff, n, 0); - logprintf(" expected\n", fn); - hexdump(buff, contents, s, 0); - } else { - logprintf(" File empty, contents should be:\n"); - hexdump(buff, NULL, s, 0); - } - failure_finish(NULL); - free(contents); - return (0); -} - -/* Verify that a text file contains the specified lines, regardless of order */ -/* This could be more efficient if we sorted both sets of lines, etc, but - * since this is used only for testing and only ever deals with a dozen or so - * lines at a time, this relatively crude approach is just fine. */ -int -assertion_file_contains_lines_any_order(const char *file, int line, - const char *pathname, const char *lines[]) -{ - char *buff; - size_t buff_size; - size_t expected_count, actual_count, i, j; - char **expected = NULL; - char *p, **actual = NULL; - char c; - int expected_failure = 0, actual_failure = 0; - - assertion_count(file, line); - - buff = slurpfile(&buff_size, "%s", pathname); - if (buff == NULL) { - failure_start(pathname, line, "Can't read file: %s", pathname); - failure_finish(NULL); - return (0); - } - - /* Make a copy of the provided lines and count up the expected - * file size. */ - for (i = 0; lines[i] != NULL; ++i) { - } - expected_count = i; - if (expected_count) { - expected = malloc(sizeof(char *) * expected_count); - if (expected == NULL) { - failure_start(pathname, line, "Can't allocate memory"); - failure_finish(NULL); - free(expected); - return (0); - } - for (i = 0; lines[i] != NULL; ++i) { - expected[i] = strdup(lines[i]); - } - } - - /* Break the file into lines */ - actual_count = 0; - for (c = '\0', p = buff; p < buff + buff_size; ++p) { - if (*p == '\x0d' || *p == '\x0a') - *p = '\0'; - if (c == '\0' && *p != '\0') - ++actual_count; - c = *p; - } - if (actual_count) { - actual = calloc(sizeof(char *), actual_count); - if (actual == NULL) { - failure_start(pathname, line, "Can't allocate memory"); - failure_finish(NULL); - free(expected); - return (0); - } - for (j = 0, p = buff; p < buff + buff_size; - p += 1 + strlen(p)) { - if (*p != '\0') { - actual[j] = p; - ++j; - } - } - } - - /* Erase matching lines from both lists */ - for (i = 0; i < expected_count; ++i) { - if (expected[i] == NULL) - continue; - for (j = 0; j < actual_count; ++j) { - if (actual[j] == NULL) - continue; - if (strcmp(expected[i], actual[j]) == 0) { - free(expected[i]); - expected[i] = NULL; - actual[j] = NULL; - break; - } - } - } - - /* If there's anything left, it's a failure */ - for (i = 0; i < expected_count; ++i) { - if (expected[i] != NULL) - ++expected_failure; - } - for (j = 0; j < actual_count; ++j) { - if (actual[j] != NULL) - ++actual_failure; - } - if (expected_failure == 0 && actual_failure == 0) { - free(buff); - free(expected); - free(actual); - return (1); - } - failure_start(file, line, "File doesn't match: %s", pathname); - for (i = 0; i < expected_count; ++i) { - if (expected[i] != NULL) { - logprintf(" Expected but not present: %s\n", expected[i]); - free(expected[i]); - } - } - for (j = 0; j < actual_count; ++j) { - if (actual[j] != NULL) - logprintf(" Present but not expected: %s\n", actual[j]); - } - failure_finish(NULL); - free(buff); - free(expected); - free(actual); - return (0); -} - -/* Verify that a text file does not contains the specified strings */ -int -assertion_file_contains_no_invalid_strings(const char *file, int line, - const char *pathname, const char *strings[]) -{ - char *buff; - int i; - - buff = slurpfile(NULL, "%s", pathname); - if (buff == NULL) { - failure_start(file, line, "Can't read file: %s", pathname); - failure_finish(NULL); - return (0); - } - - for (i = 0; strings[i] != NULL; ++i) { - if (strstr(buff, strings[i]) != NULL) { - failure_start(file, line, "Invalid string in %s: %s", pathname, - strings[i]); - failure_finish(NULL); - free(buff); - return(0); - } - } - - free(buff); - return (0); -} - -/* Test that two paths point to the same file. */ -/* As a side-effect, asserts that both files exist. */ -static int -is_hardlink(const char *file, int line, - const char *path1, const char *path2) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2; - int r; - - assertion_count(file, line); - r = my_GetFileInformationByName(path1, &bhfi1); - if (r == 0) { - failure_start(file, line, "File %s can't be inspected?", path1); - failure_finish(NULL); - return (0); - } - r = my_GetFileInformationByName(path2, &bhfi2); - if (r == 0) { - failure_start(file, line, "File %s can't be inspected?", path2); - failure_finish(NULL); - return (0); - } - return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber - && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh - && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow); -#else - struct stat st1, st2; - int r; - - assertion_count(file, line); - r = lstat(path1, &st1); - if (r != 0) { - failure_start(file, line, "File should exist: %s", path1); - failure_finish(NULL); - return (0); - } - r = lstat(path2, &st2); - if (r != 0) { - failure_start(file, line, "File should exist: %s", path2); - failure_finish(NULL); - return (0); - } - return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev); -#endif -} - -int -assertion_is_hardlink(const char *file, int line, - const char *path1, const char *path2) -{ - if (is_hardlink(file, line, path1, path2)) - return (1); - failure_start(file, line, - "Files %s and %s are not hardlinked", path1, path2); - failure_finish(NULL); - return (0); -} - -int -assertion_is_not_hardlink(const char *file, int line, - const char *path1, const char *path2) -{ - if (!is_hardlink(file, line, path1, path2)) - return (1); - failure_start(file, line, - "Files %s and %s should not be hardlinked", path1, path2); - failure_finish(NULL); - return (0); -} - -/* Verify a/b/mtime of 'pathname'. */ -/* If 'recent', verify that it's within last 10 seconds. */ -static int -assertion_file_time(const char *file, int line, - const char *pathname, long t, long nsec, char type, int recent) -{ - long long filet, filet_nsec; - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) -#define EPOC_TIME (116444736000000000ULL) - FILETIME fxtime, fbirthtime, fatime, fmtime; - ULARGE_INTEGER wintm; - HANDLE h; - fxtime.dwLowDateTime = 0; - fxtime.dwHighDateTime = 0; - - assertion_count(file, line); - /* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open - * a directory file. If not, CreateFile() will fail when - * the pathname is a directory. */ - h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) { - failure_start(file, line, "Can't access %s\n", pathname); - failure_finish(NULL); - return (0); - } - r = GetFileTime(h, &fbirthtime, &fatime, &fmtime); - switch (type) { - case 'a': fxtime = fatime; break; - case 'b': fxtime = fbirthtime; break; - case 'm': fxtime = fmtime; break; - } - CloseHandle(h); - if (r == 0) { - failure_start(file, line, "Can't GetFileTime %s\n", pathname); - failure_finish(NULL); - return (0); - } - wintm.LowPart = fxtime.dwLowDateTime; - wintm.HighPart = fxtime.dwHighDateTime; - filet = (wintm.QuadPart - EPOC_TIME) / 10000000; - filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100; - nsec = (nsec / 100) * 100; /* Round the request */ -#else - struct stat st; - - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0) { - failure_start(file, line, "Can't stat %s\n", pathname); - failure_finish(NULL); - return (0); - } - switch (type) { - case 'a': filet = st.st_atime; break; - case 'm': filet = st.st_mtime; break; - case 'b': filet = 0; break; - default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); - exit(1); - } -#if defined(__FreeBSD__) - switch (type) { - case 'a': filet_nsec = st.st_atimespec.tv_nsec; break; - case 'b': filet = st.st_birthtime; - /* FreeBSD filesystems that don't support birthtime - * (e.g., UFS1) always return -1 here. */ - if (filet == -1) { - return (1); - } - filet_nsec = st.st_birthtimespec.tv_nsec; break; - case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break; - default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); - exit(1); - } - /* FreeBSD generally only stores to microsecond res, so round. */ - filet_nsec = (filet_nsec / 1000) * 1000; - nsec = (nsec / 1000) * 1000; -#else - filet_nsec = nsec = 0; /* Generic POSIX only has whole seconds. */ - if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */ -#if defined(__HAIKU__) - if (type == 'a') return (1); /* Haiku doesn't have atime. */ -#endif -#endif -#endif - if (recent) { - /* Check that requested time is up-to-date. */ - time_t now = time(NULL); - if (filet < now - 10 || filet > now + 1) { - failure_start(file, line, - "File %s has %ctime %lld, %lld seconds ago\n", - pathname, type, filet, now - filet); - failure_finish(NULL); - return (0); - } - } else if (filet != t || filet_nsec != nsec) { - failure_start(file, line, - "File %s has %ctime %lld.%09lld, expected %lld.%09lld", - pathname, type, filet, filet_nsec, t, nsec); - failure_finish(NULL); - return (0); - } - return (1); -} - -/* Verify atime of 'pathname'. */ -int -assertion_file_atime(const char *file, int line, - const char *pathname, long t, long nsec) -{ - return assertion_file_time(file, line, pathname, t, nsec, 'a', 0); -} - -/* Verify atime of 'pathname' is up-to-date. */ -int -assertion_file_atime_recent(const char *file, int line, const char *pathname) -{ - return assertion_file_time(file, line, pathname, 0, 0, 'a', 1); -} - -/* Verify birthtime of 'pathname'. */ -int -assertion_file_birthtime(const char *file, int line, - const char *pathname, long t, long nsec) -{ - return assertion_file_time(file, line, pathname, t, nsec, 'b', 0); -} - -/* Verify birthtime of 'pathname' is up-to-date. */ -int -assertion_file_birthtime_recent(const char *file, int line, - const char *pathname) -{ - return assertion_file_time(file, line, pathname, 0, 0, 'b', 1); -} - -/* Verify mode of 'pathname'. */ -int -assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode) -{ - int mode; - int r; - - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - failure_start(file, line, "assertFileMode not yet implemented for Windows"); - (void)mode; /* UNUSED */ - (void)r; /* UNUSED */ -#else - { - struct stat st; - r = lstat(pathname, &st); - mode = (int)(st.st_mode & 0777); - } - if (r == 0 && mode == expected_mode) - return (1); - failure_start(file, line, "File %s has mode %o, expected %o", - pathname, mode, expected_mode); -#endif - failure_finish(NULL); - return (0); -} - -/* Verify mtime of 'pathname'. */ -int -assertion_file_mtime(const char *file, int line, - const char *pathname, long t, long nsec) -{ - return assertion_file_time(file, line, pathname, t, nsec, 'm', 0); -} - -/* Verify mtime of 'pathname' is up-to-date. */ -int -assertion_file_mtime_recent(const char *file, int line, const char *pathname) -{ - return assertion_file_time(file, line, pathname, 0, 0, 'm', 1); -} - -/* Verify number of links to 'pathname'. */ -int -assertion_file_nlinks(const char *file, int line, - const char *pathname, int nlinks) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - BY_HANDLE_FILE_INFORMATION bhfi; - int r; - - assertion_count(file, line); - r = my_GetFileInformationByName(pathname, &bhfi); - if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks) - return (1); - failure_start(file, line, "File %s has %d links, expected %d", - pathname, bhfi.nNumberOfLinks, nlinks); - failure_finish(NULL); - return (0); -#else - struct stat st; - int r; - - assertion_count(file, line); - r = lstat(pathname, &st); - if (r == 0 && (int)st.st_nlink == nlinks) - return (1); - failure_start(file, line, "File %s has %d links, expected %d", - pathname, st.st_nlink, nlinks); - failure_finish(NULL); - return (0); -#endif -} - -/* Verify size of 'pathname'. */ -int -assertion_file_size(const char *file, int line, const char *pathname, long size) -{ - int64_t filesize; - int r; - - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - { - BY_HANDLE_FILE_INFORMATION bhfi; - r = !my_GetFileInformationByName(pathname, &bhfi); - filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow; - } -#else - { - struct stat st; - r = lstat(pathname, &st); - filesize = st.st_size; - } -#endif - if (r == 0 && filesize == size) - return (1); - failure_start(file, line, "File %s has size %ld, expected %ld", - pathname, (long)filesize, (long)size); - failure_finish(NULL); - return (0); -} - -/* Assert that 'pathname' is a dir. If mode >= 0, verify that too. */ -int -assertion_is_dir(const char *file, int line, const char *pathname, int mode) -{ - struct stat st; - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)mode; /* UNUSED */ -#endif - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0) { - failure_start(file, line, "Dir should exist: %s", pathname); - failure_finish(NULL); - return (0); - } - if (!S_ISDIR(st.st_mode)) { - failure_start(file, line, "%s is not a dir", pathname); - failure_finish(NULL); - return (0); - } -#if !defined(_WIN32) || defined(__CYGWIN__) - /* Windows doesn't handle permissions the same way as POSIX, - * so just ignore the mode tests. */ - /* TODO: Can we do better here? */ - if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { - failure_start(file, line, "Dir %s has wrong mode", pathname); - logprintf(" Expected: 0%3o\n", mode); - logprintf(" Found: 0%3o\n", st.st_mode & 07777); - failure_finish(NULL); - return (0); - } -#endif - return (1); -} - -/* Verify that 'pathname' is a regular file. If 'mode' is >= 0, - * verify that too. */ -int -assertion_is_reg(const char *file, int line, const char *pathname, int mode) -{ - struct stat st; - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)mode; /* UNUSED */ -#endif - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0 || !S_ISREG(st.st_mode)) { - failure_start(file, line, "File should exist: %s", pathname); - failure_finish(NULL); - return (0); - } -#if !defined(_WIN32) || defined(__CYGWIN__) - /* Windows doesn't handle permissions the same way as POSIX, - * so just ignore the mode tests. */ - /* TODO: Can we do better here? */ - if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { - failure_start(file, line, "File %s has wrong mode", pathname); - logprintf(" Expected: 0%3o\n", mode); - logprintf(" Found: 0%3o\n", st.st_mode & 07777); - failure_finish(NULL); - return (0); - } -#endif - return (1); -} - -/* Check whether 'pathname' is a symbolic link. If 'contents' is - * non-NULL, verify that the symlink has those contents. */ -static int -is_symlink(const char *file, int line, - const char *pathname, const char *contents) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)pathname; /* UNUSED */ - (void)contents; /* UNUSED */ - assertion_count(file, line); - /* Windows sort-of has real symlinks, but they're only usable - * by privileged users and are crippled even then, so there's - * really not much point in bothering with this. */ - return (0); -#else - char buff[300]; - struct stat st; - ssize_t linklen; - int r; - - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0) { - failure_start(file, line, - "Symlink should exist: %s", pathname); - failure_finish(NULL); - return (0); - } - if (!S_ISLNK(st.st_mode)) - return (0); - if (contents == NULL) - return (1); - linklen = readlink(pathname, buff, sizeof(buff)); - if (linklen < 0) { - failure_start(file, line, "Can't read symlink %s", pathname); - failure_finish(NULL); - return (0); - } - buff[linklen] = '\0'; - if (strcmp(buff, contents) != 0) - return (0); - return (1); -#endif -} - -/* Assert that path is a symlink that (optionally) contains contents. */ -int -assertion_is_symlink(const char *file, int line, - const char *path, const char *contents) -{ - if (is_symlink(file, line, path, contents)) - return (1); - if (contents) - failure_start(file, line, "File %s is not a symlink to %s", - path, contents); - else - failure_start(file, line, "File %s is not a symlink", path); - failure_finish(NULL); - return (0); -} - - -/* Create a directory and report any errors. */ -int -assertion_make_dir(const char *file, int line, const char *dirname, int mode) -{ - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)mode; /* UNUSED */ - if (0 == _mkdir(dirname)) - return (1); -#else - if (0 == mkdir(dirname, mode)) { - if (0 == chmod(dirname, mode)) { - assertion_file_mode(file, line, dirname, mode); - return (1); - } - } -#endif - failure_start(file, line, "Could not create directory %s", dirname); - failure_finish(NULL); - return(0); -} - -/* Create a file with the specified contents and report any failures. */ -int -assertion_make_file(const char *file, int line, - const char *path, int mode, int csize, const void *contents) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* TODO: Rework this to set file mode as well. */ - FILE *f; - (void)mode; /* UNUSED */ - assertion_count(file, line); - f = fopen(path, "wb"); - if (f == NULL) { - failure_start(file, line, "Could not create file %s", path); - failure_finish(NULL); - return (0); - } - if (contents != NULL) { - size_t wsize; - - if (csize < 0) - wsize = strlen(contents); - else - wsize = (size_t)csize; - if (wsize != fwrite(contents, 1, wsize, f)) { - fclose(f); - failure_start(file, line, - "Could not write file %s", path); - failure_finish(NULL); - return (0); - } - } - fclose(f); - return (1); -#else - int fd; - assertion_count(file, line); - fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644); - if (fd < 0) { - failure_start(file, line, "Could not create %s", path); - failure_finish(NULL); - return (0); - } - if (0 != chmod(path, mode)) { - failure_start(file, line, "Could not chmod %s", path); - failure_finish(NULL); - close(fd); - return (0); - } - if (contents != NULL) { - ssize_t wsize; - - if (csize < 0) - wsize = (ssize_t)strlen(contents); - else - wsize = (ssize_t)csize; - if (wsize != write(fd, contents, wsize)) { - close(fd); - failure_start(file, line, - "Could not write to %s", path); - failure_finish(NULL); - close(fd); - return (0); - } - } - close(fd); - assertion_file_mode(file, line, path, mode); - return (1); -#endif -} - -/* Create a hardlink and report any failures. */ -int -assertion_make_hardlink(const char *file, int line, - const char *newpath, const char *linkto) -{ - int succeeded; - - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - succeeded = my_CreateHardLinkA(newpath, linkto); -#elif HAVE_LINK - succeeded = !link(linkto, newpath); -#else - succeeded = 0; -#endif - if (succeeded) - return (1); - failure_start(file, line, "Could not create hardlink"); - logprintf(" New link: %s\n", newpath); - logprintf(" Old name: %s\n", linkto); - failure_finish(NULL); - return(0); -} - -/* Create a symlink and report any failures. */ -int -assertion_make_symlink(const char *file, int line, - const char *newpath, const char *linkto) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - int targetIsDir = 0; /* TODO: Fix this */ - assertion_count(file, line); - if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir)) - return (1); -#elif HAVE_SYMLINK - assertion_count(file, line); - if (0 == symlink(linkto, newpath)) - return (1); -#endif - failure_start(file, line, "Could not create symlink"); - logprintf(" New link: %s\n", newpath); - logprintf(" Old name: %s\n", linkto); - failure_finish(NULL); - return(0); -} - -/* Set umask, report failures. */ -int -assertion_umask(const char *file, int line, int mask) -{ - assertion_count(file, line); - (void)file; /* UNUSED */ - (void)line; /* UNUSED */ - umask(mask); - return (1); -} - -/* Set times, report failures. */ -int -assertion_utimes(const char *file, int line, - const char *pathname, long at, long at_nsec, long mt, long mt_nsec) -{ - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) -#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\ - + (((nsec)/1000)*10)) - HANDLE h; - ULARGE_INTEGER wintm; - FILETIME fatime, fmtime; - FILETIME *pat, *pmt; - - assertion_count(file, line); - h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) { - failure_start(file, line, "Can't access %s\n", pathname); - failure_finish(NULL); - return (0); - } - - if (at > 0 || at_nsec > 0) { - wintm.QuadPart = WINTIME(at, at_nsec); - fatime.dwLowDateTime = wintm.LowPart; - fatime.dwHighDateTime = wintm.HighPart; - pat = &fatime; - } else - pat = NULL; - if (mt > 0 || mt_nsec > 0) { - wintm.QuadPart = WINTIME(mt, mt_nsec); - fmtime.dwLowDateTime = wintm.LowPart; - fmtime.dwHighDateTime = wintm.HighPart; - pmt = &fmtime; - } else - pmt = NULL; - if (pat != NULL || pmt != NULL) - r = SetFileTime(h, NULL, pat, pmt); - else - r = 1; - CloseHandle(h); - if (r == 0) { - failure_start(file, line, "Can't SetFileTime %s\n", pathname); - failure_finish(NULL); - return (0); - } - return (1); -#else /* defined(_WIN32) && !defined(__CYGWIN__) */ - struct stat st; - struct timeval times[2]; - -#if !defined(__FreeBSD__) - mt_nsec = at_nsec = 0; /* Generic POSIX only has whole seconds. */ -#endif - if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0) - return (1); - - r = lstat(pathname, &st); - if (r < 0) { - failure_start(file, line, "Can't stat %s\n", pathname); - failure_finish(NULL); - return (0); - } - - if (mt == 0 && mt_nsec == 0) { - mt = st.st_mtime; -#if defined(__FreeBSD__) - mt_nsec = st.st_mtimespec.tv_nsec; - /* FreeBSD generally only stores to microsecond res, so round. */ - mt_nsec = (mt_nsec / 1000) * 1000; -#endif - } - if (at == 0 && at_nsec == 0) { - at = st.st_atime; -#if defined(__FreeBSD__) - at_nsec = st.st_atimespec.tv_nsec; - /* FreeBSD generally only stores to microsecond res, so round. */ - at_nsec = (at_nsec / 1000) * 1000; -#endif - } - - times[1].tv_sec = mt; - times[1].tv_usec = mt_nsec / 1000; - - times[0].tv_sec = at; - times[0].tv_usec = at_nsec / 1000; - -#ifdef HAVE_LUTIMES - r = lutimes(pathname, times); -#else - r = utimes(pathname, times); -#endif - if (r < 0) { - failure_start(file, line, "Can't utimes %s\n", pathname); - failure_finish(NULL); - return (0); - } - return (1); -#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ -} - -/* Set nodump, report failures. */ -int -assertion_nodump(const char *file, int line, const char *pathname) -{ -#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) - int r; - - assertion_count(file, line); - r = chflags(pathname, UF_NODUMP); - if (r < 0) { - failure_start(file, line, "Can't set nodump %s\n", pathname); - failure_finish(NULL); - return (0); - } -#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ - && defined(EXT2_NODUMP_FL) - int fd, r, flags; - - assertion_count(file, line); - fd = open(pathname, O_RDONLY | O_NONBLOCK); - if (fd < 0) { - failure_start(file, line, "Can't open %s\n", pathname); - failure_finish(NULL); - return (0); - } - r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); - if (r < 0) { - failure_start(file, line, "Can't get flags %s\n", pathname); - failure_finish(NULL); - return (0); - } - flags |= EXT2_NODUMP_FL; - r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); - if (r < 0) { - failure_start(file, line, "Can't set nodump %s\n", pathname); - failure_finish(NULL); - return (0); - } - close(fd); -#else - (void)pathname; /* UNUSED */ - assertion_count(file, line); -#endif - return (1); -} - -/* - * - * UTILITIES for use by tests. - * - */ - -/* - * Check whether platform supports symlinks. This is intended - * for tests to use in deciding whether to bother testing symlink - * support; if the platform doesn't support symlinks, there's no point - * in checking whether the program being tested can create them. - * - * Note that the first time this test is called, we actually go out to - * disk to create and verify a symlink. This is necessary because - * symlink support is actually a property of a particular filesystem - * and can thus vary between directories on a single system. After - * the first call, this returns the cached result from memory, so it's - * safe to call it as often as you wish. - */ -int -canSymlink(void) -{ - /* Remember the test result */ - static int value = 0, tested = 0; - if (tested) - return (value); - - ++tested; - assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a"); - /* Note: Cygwin has its own symlink() emulation that does not - * use the Win32 CreateSymbolicLink() function. */ -#if defined(_WIN32) && !defined(__CYGWIN__) - value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0) - && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0"); -#elif HAVE_SYMLINK - value = (0 == symlink("canSymlink.0", "canSymlink.1")) - && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0"); -#endif - return (value); -} - -/* Platform-dependent options for hiding the output of a subcommand. */ -#if defined(_WIN32) && !defined(__CYGWIN__) -static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */ -#else -static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */ -#endif -/* - * Can this platform run the bzip2 program? - */ -int -canBzip2(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("bzip2 -d -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the grzip program? - */ -int -canGrzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("grzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the gzip program? - */ -int -canGzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("gzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lrzip program? - */ -int -canRunCommand(const char *cmd) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("%s %s", cmd, redirectArgs) == 0) - value = 1; - } - return (value); -} - -int -canLrzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lrzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lz4 program? - */ -int -canLz4(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lz4 -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lzip program? - */ -int -canLzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lzma program? - */ -int -canLzma(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzma -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lzop program? - */ -int -canLzop(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzop -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the xz program? - */ -int -canXz(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("xz -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this filesystem handle nodump flags. - */ -#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) - -int -canNodump(void) -{ - const char *path = "cannodumptest"; - struct stat sb; - - assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); - if (chflags(path, UF_NODUMP) < 0) - return (0); - if (stat(path, &sb) < 0) - return (0); - if (sb.st_flags & UF_NODUMP) - return (1); - return (0); -} - -#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ - && defined(EXT2_NODUMP_FL) - -int -canNodump(void) -{ - const char *path = "cannodumptest"; - int fd, r, flags; - - assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) - return (0); - r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); - if (r < 0) - return (0); - flags |= EXT2_NODUMP_FL; - r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); - if (r < 0) - return (0); - close(fd); - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) - return (0); - r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); - if (r < 0) - return (0); - close(fd); - if (flags & EXT2_NODUMP_FL) - return (1); - return (0); -} - -#else - -int -canNodump() -{ - return (0); -} - -#endif - -/* - * Sleep as needed; useful for verifying disk timestamp changes by - * ensuring that the wall-clock time has actually changed before we - * go back to re-read something from disk. - */ -void -sleepUntilAfter(time_t t) -{ - while (t >= time(NULL)) -#if defined(_WIN32) && !defined(__CYGWIN__) - Sleep(500); -#else - sleep(1); -#endif -} - -/* - * Call standard system() call, but build up the command line using - * sprintf() conventions. - */ -int -systemf(const char *fmt, ...) -{ - char buff[8192]; - va_list ap; - int r; - - va_start(ap, fmt); - vsprintf(buff, fmt, ap); - if (verbosity > VERBOSITY_FULL) - logprintf("Cmd: %s\n", buff); - r = system(buff); - va_end(ap); - return (r); -} - -/* - * Slurp a file into memory for ease of comparison and testing. - * Returns size of file in 'sizep' if non-NULL, null-terminates - * data in memory for ease of use. - */ -char * -slurpfile(size_t * sizep, const char *fmt, ...) -{ - char filename[8192]; - struct stat st; - va_list ap; - char *p; - ssize_t bytes_read; - FILE *f; - int r; - - va_start(ap, fmt); - vsprintf(filename, fmt, ap); - va_end(ap); - - f = fopen(filename, "rb"); - if (f == NULL) { - /* Note: No error; non-existent file is okay here. */ - return (NULL); - } - r = fstat(fileno(f), &st); - if (r != 0) { - logprintf("Can't stat file %s\n", filename); - fclose(f); - return (NULL); - } - p = malloc((size_t)st.st_size + 1); - if (p == NULL) { - logprintf("Can't allocate %ld bytes of memory to read file %s\n", - (long int)st.st_size, filename); - fclose(f); - return (NULL); - } - bytes_read = fread(p, 1, (size_t)st.st_size, f); - if (bytes_read < st.st_size) { - logprintf("Can't read file %s\n", filename); - fclose(f); - free(p); - return (NULL); - } - p[st.st_size] = '\0'; - if (sizep != NULL) - *sizep = (size_t)st.st_size; - fclose(f); - return (p); -} - -/* - * Slurp a file into memory for ease of comparison and testing. - * Returns size of file in 'sizep' if non-NULL, null-terminates - * data in memory for ease of use. - */ -void -dumpfile(const char *filename, void *data, size_t len) -{ - ssize_t bytes_written; - FILE *f; - - f = fopen(filename, "wb"); - if (f == NULL) { - logprintf("Can't open file %s for writing\n", filename); - return; - } - bytes_written = fwrite(data, 1, len, f); - if (bytes_written < (ssize_t)len) - logprintf("Can't write file %s\n", filename); - fclose(f); -} - -/* Read a uuencoded file from the reference directory, decode, and - * write the result into the current directory. */ -#define VALID_UUDECODE(c) (c >= 32 && c <= 96) -#define UUDECODE(c) (((c) - 0x20) & 0x3f) -void -extract_reference_file(const char *name) -{ - char buff[1024]; - FILE *in, *out; - - sprintf(buff, "%s/%s.uu", refdir, name); - in = fopen(buff, "r"); - failure("Couldn't open reference file %s", buff); - assert(in != NULL); - if (in == NULL) - return; - /* Read up to and including the 'begin' line. */ - for (;;) { - if (fgets(buff, sizeof(buff), in) == NULL) { - /* TODO: This is a failure. */ - return; - } - if (memcmp(buff, "begin ", 6) == 0) - break; - } - /* Now, decode the rest and write it. */ - out = fopen(name, "wb"); - while (fgets(buff, sizeof(buff), in) != NULL) { - char *p = buff; - int bytes; - - if (memcmp(buff, "end", 3) == 0) - break; - - bytes = UUDECODE(*p++); - while (bytes > 0) { - int n = 0; - /* Write out 1-3 bytes from that. */ - if (bytes > 0) { - assert(VALID_UUDECODE(p[0])); - assert(VALID_UUDECODE(p[1])); - n = UUDECODE(*p++) << 18; - n |= UUDECODE(*p++) << 12; - fputc(n >> 16, out); - --bytes; - } - if (bytes > 0) { - assert(VALID_UUDECODE(p[0])); - n |= UUDECODE(*p++) << 6; - fputc((n >> 8) & 0xFF, out); - --bytes; - } - if (bytes > 0) { - assert(VALID_UUDECODE(p[0])); - n |= UUDECODE(*p++); - fputc(n & 0xFF, out); - --bytes; - } - } - } - fclose(out); - fclose(in); -} - -void -copy_reference_file(const char *name) -{ - char buff[1024]; - FILE *in, *out; - size_t rbytes; - - sprintf(buff, "%s/%s", refdir, name); - in = fopen(buff, "rb"); - failure("Couldn't open reference file %s", buff); - assert(in != NULL); - if (in == NULL) - return; - /* Now, decode the rest and write it. */ - /* Not a lot of error checking here; the input better be right. */ - out = fopen(name, "wb"); - while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) { - if (fwrite(buff, 1, rbytes, out) != rbytes) { - logprintf("Error: fwrite\n"); - break; - } - } - fclose(out); - fclose(in); -} - -int -is_LargeInode(const char *file) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - BY_HANDLE_FILE_INFORMATION bhfi; - int r; - - r = my_GetFileInformationByName(file, &bhfi); - if (r != 0) - return (0); - return (bhfi.nFileIndexHigh & 0x0000FFFFUL); -#else - struct stat st; - int64_t ino; - - if (stat(file, &st) < 0) - return (0); - ino = (int64_t)st.st_ino; - return (ino > 0xffffffff); -#endif -} - -void -extract_reference_files(const char **names) -{ - while (names && *names) - extract_reference_file(*names++); -} - -/* - * - * TEST management - * - */ - -/* - * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has - * a line like - * DEFINE_TEST(test_function) - * for each test. - */ - -/* Use "list.h" to declare all of the test functions. */ -#undef DEFINE_TEST -#define DEFINE_TEST(name) void name(void); -#include "list.h" - -/* Use "list.h" to create a list of all tests (functions and names). */ -#undef DEFINE_TEST -#define DEFINE_TEST(n) { n, #n, 0 }, -struct test_list_t tests[] = { - #include "list.h" -}; - -/* - * Summarize repeated failures in the just-completed test. - */ -static void -test_summarize(int failed, int skips_num) -{ - unsigned int i; - - switch (verbosity) { - case VERBOSITY_SUMMARY_ONLY: - printf(failed ? "E" : "."); - fflush(stdout); - break; - case VERBOSITY_PASSFAIL: - printf(failed ? "FAIL\n" : skips_num ? "ok (S)\n" : "ok\n"); - break; - } - - log_console = (verbosity == VERBOSITY_LIGHT_REPORT); - - for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { - if (failed_lines[i].count > 1 && !failed_lines[i].skip) - logprintf("%s:%d: Summary: Failed %d times\n", - failed_filename, i, failed_lines[i].count); - } - /* Clear the failure history for the next file. */ - failed_filename = NULL; - memset(failed_lines, 0, sizeof(failed_lines)); -} - -/* - * Actually run a single test, with appropriate setup and cleanup. - */ -static int -test_run(int i, const char *tmpdir) -{ - char workdir[1024]; - char logfilename[64]; - int failures_before = failures; - int skips_before = skips; - int oldumask; - - switch (verbosity) { - case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */ - break; - case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */ - printf("%3d: %-64s", i, tests[i].name); - fflush(stdout); - break; - default: /* Title of test, details will follow */ - printf("%3d: %s\n", i, tests[i].name); - } - - /* Chdir to the top-level work directory. */ - if (!assertChdir(tmpdir)) { - fprintf(stderr, - "ERROR: Can't chdir to top work dir %s\n", tmpdir); - exit(1); - } - /* Create a log file for this test. */ - sprintf(logfilename, "%s.log", tests[i].name); - logfile = fopen(logfilename, "w"); - fprintf(logfile, "%s\n\n", tests[i].name); - /* Chdir() to a work dir for this specific test. */ - snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name); - testworkdir = workdir; - if (!assertMakeDir(testworkdir, 0755) - || !assertChdir(testworkdir)) { - fprintf(stderr, - "ERROR: Can't chdir to work dir %s\n", testworkdir); - exit(1); - } - /* Explicitly reset the locale before each test. */ - setlocale(LC_ALL, "C"); - /* Record the umask before we run the test. */ - umask(oldumask = umask(0)); - /* - * Run the actual test. - */ - (*tests[i].func)(); - /* - * Clean up and report afterwards. - */ - testworkdir = NULL; - /* Restore umask */ - umask(oldumask); - /* Reset locale. */ - setlocale(LC_ALL, "C"); - /* Reset directory. */ - if (!assertChdir(tmpdir)) { - fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n", - tmpdir); - exit(1); - } - /* Report per-test summaries. */ - tests[i].failures = failures - failures_before; - test_summarize(tests[i].failures, skips - skips_before); - /* Close the per-test log file. */ - fclose(logfile); - logfile = NULL; - /* If there were no failures, we can remove the work dir and logfile. */ - if (tests[i].failures == 0) { - if (!keep_temp_files && assertChdir(tmpdir)) { -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure not to leave empty directories. - * Sometimes a processing of closing files used by tests - * is not done, then rmdir will be failed and it will - * leave a empty test directory. So we should wait a few - * seconds and retry rmdir. */ - int r, t; - for (t = 0; t < 10; t++) { - if (t > 0) - Sleep(1000); - r = systemf("rmdir /S /Q %s", tests[i].name); - if (r == 0) - break; - } - systemf("del %s", logfilename); -#else - systemf("rm -rf %s", tests[i].name); - systemf("rm %s", logfilename); -#endif - } - } - /* Return appropriate status. */ - return (tests[i].failures); -} - -/* - * - * - * MAIN and support routines. - * - * - */ - -static void -usage(const char *program) -{ - static const int limit = sizeof(tests) / sizeof(tests[0]); - int i; - - printf("Usage: %s [options] <test> <test> ...\n", program); - printf("Default is to run all tests.\n"); - printf("Otherwise, specify the numbers of the tests you wish to run.\n"); - printf("Options:\n"); - printf(" -d Dump core after any failure, for debugging.\n"); - printf(" -k Keep all temp files.\n"); - printf(" Default: temp files for successful tests deleted.\n"); -#ifdef PROGRAM - printf(" -p <path> Path to executable to be tested.\n"); - printf(" Default: path taken from " ENVBASE " environment variable.\n"); -#endif - printf(" -q Quiet.\n"); - printf(" -r <dir> Path to dir containing reference files.\n"); - printf(" Default: Current directory.\n"); - printf(" -u Keep running specifies tests until one fails.\n"); - printf(" -v Verbose.\n"); - printf("Available tests:\n"); - for (i = 0; i < limit; i++) - printf(" %d: %s\n", i, tests[i].name); - exit(1); -} - -static char * -get_refdir(const char *d) -{ - size_t tried_size, buff_size; - char *buff, *tried, *pwd = NULL, *p = NULL; - -#ifdef PATH_MAX - buff_size = PATH_MAX; -#else - buff_size = 8192; -#endif - buff = calloc(buff_size, 1); - if (buff == NULL) { - fprintf(stderr, "Unable to allocate memory\n"); - exit(1); - } - - /* Allocate a buffer to hold the various directories we checked. */ - tried_size = buff_size * 2; - tried = calloc(tried_size, 1); - if (tried == NULL) { - fprintf(stderr, "Unable to allocate memory\n"); - exit(1); - } - - /* If a dir was specified, try that */ - if (d != NULL) { - pwd = NULL; - snprintf(buff, buff_size, "%s", d); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - goto failure; - } - - /* Get the current dir. */ -#ifdef PATH_MAX - pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ -#else - pwd = getcwd(NULL, 0); -#endif - while (pwd[strlen(pwd) - 1] == '\n') - pwd[strlen(pwd) - 1] = '\0'; - - /* Look for a known file. */ - snprintf(buff, buff_size, "%s", pwd); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - - snprintf(buff, buff_size, "%s/test", pwd); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - -#if defined(LIBRARY) - snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY); -#else - snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM); -#endif - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - -#if defined(PROGRAM_ALIAS) - snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); -#endif - - if (memcmp(pwd, "/usr/obj", 8) == 0) { - snprintf(buff, buff_size, "%s", pwd + 8); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - - snprintf(buff, buff_size, "%s/test", pwd + 8); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - } - -failure: - printf("Unable to locate known reference file %s\n", KNOWNREF); - printf(" Checked following directories:\n%s\n", tried); - printf("Use -r option to specify full path to reference directory\n"); -#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) - DebugBreak(); -#endif - exit(1); - -success: - free(p); - free(pwd); - free(tried); - - /* Copy result into a fresh buffer to reduce memory usage. */ - p = strdup(buff); - free(buff); - return p; -} - -int -main(int argc, char **argv) -{ - static const int limit = sizeof(tests) / sizeof(tests[0]); - int test_set[sizeof(tests) / sizeof(tests[0])]; - int i = 0, j = 0, tests_run = 0, tests_failed = 0, option; - time_t now; - char *refdir_alloc = NULL; - const char *progname; - char **saved_argv; - const char *tmp, *option_arg, *p; - char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL; - char tmpdir_timestamp[256]; - - (void)argc; /* UNUSED */ - - /* Get the current dir. */ -#ifdef PATH_MAX - pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ -#else - pwd = getcwd(NULL, 0); -#endif - while (pwd[strlen(pwd) - 1] == '\n') - pwd[strlen(pwd) - 1] = '\0'; - -#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__) - /* To stop to run the default invalid parameter handler. */ - _set_invalid_parameter_handler(invalid_parameter_handler); - /* Disable annoying assertion message box. */ - _CrtSetReportMode(_CRT_ASSERT, 0); -#endif - - /* - * Name of this program, used to build root of our temp directory - * tree. - */ - progname = p = argv[0]; - if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL) - { - fprintf(stderr, "ERROR: Out of memory."); - exit(1); - } - strcpy(testprogdir, progname); - while (*p != '\0') { - /* Support \ or / dir separators for Windows compat. */ - if (*p == '/' || *p == '\\') - { - progname = p + 1; - i = j; - } - ++p; - j++; - } - testprogdir[i] = '\0'; -#if defined(_WIN32) && !defined(__CYGWIN__) - if (testprogdir[0] != '/' && testprogdir[0] != '\\' && - !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') || - (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) && - testprogdir[1] == ':' && - (testprogdir[2] == '/' || testprogdir[2] == '\\'))) -#else - if (testprogdir[0] != '/') -#endif - { - /* Fixup path for relative directories. */ - if ((testprogdir = (char *)realloc(testprogdir, - strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL) - { - fprintf(stderr, "ERROR: Out of memory."); - exit(1); - } - memmove(testprogdir + strlen(pwd) + 1, testprogdir, - strlen(testprogdir) + 1); - memcpy(testprogdir, pwd, strlen(pwd)); - testprogdir[strlen(pwd)] = '/'; - } - -#ifdef PROGRAM - /* Get the target program from environment, if available. */ - testprogfile = getenv(ENVBASE); -#endif - - if (getenv("TMPDIR") != NULL) - tmp = getenv("TMPDIR"); - else if (getenv("TMP") != NULL) - tmp = getenv("TMP"); - else if (getenv("TEMP") != NULL) - tmp = getenv("TEMP"); - else if (getenv("TEMPDIR") != NULL) - tmp = getenv("TEMPDIR"); - else - tmp = "/tmp"; - - /* Allow -d to be controlled through the environment. */ - if (getenv(ENVBASE "_DEBUG") != NULL) - dump_on_failure = 1; - - /* Allow -v to be controlled through the environment. */ - if (getenv("_VERBOSITY_LEVEL") != NULL) - { - vlevel = getenv("_VERBOSITY_LEVEL"); - verbosity = atoi(vlevel); - if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL) - { - /* Unsupported verbosity levels are silently ignored */ - vlevel = NULL; - verbosity = VERBOSITY_PASSFAIL; - } - } - - /* Get the directory holding test files from environment. */ - refdir = getenv(ENVBASE "_TEST_FILES"); - - /* - * Parse options, without using getopt(), which isn't available - * on all platforms. - */ - ++argv; /* Skip program name */ - while (*argv != NULL) { - if (**argv != '-') - break; - p = *argv++; - ++p; /* Skip '-' */ - while (*p != '\0') { - option = *p++; - option_arg = NULL; - /* If 'opt' takes an argument, parse that. */ - if (option == 'p' || option == 'r') { - if (*p != '\0') - option_arg = p; - else if (*argv == NULL) { - fprintf(stderr, - "Option -%c requires argument.\n", - option); - usage(progname); - } else - option_arg = *argv++; - p = ""; /* End of this option word. */ - } - - /* Now, handle the option. */ - switch (option) { - case 'd': - dump_on_failure = 1; - break; - case 'k': - keep_temp_files = 1; - break; - case 'p': -#ifdef PROGRAM - testprogfile = option_arg; -#else - fprintf(stderr, "-p option not permitted\n"); - usage(progname); -#endif - break; - case 'q': - if (!vlevel) - verbosity--; - break; - case 'r': - refdir = option_arg; - break; - case 'u': - until_failure++; - break; - case 'v': - if (!vlevel) - verbosity++; - break; - default: - fprintf(stderr, "Unrecognized option '%c'\n", - option); - usage(progname); - } - } - } - - /* - * Sanity-check that our options make sense. - */ -#ifdef PROGRAM - if (testprogfile == NULL) - { - if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 + - strlen(PROGRAM) + 1)) == NULL) - { - fprintf(stderr, "ERROR: Out of memory."); - exit(1); - } - strcpy(tmp2, testprogdir); - strcat(tmp2, "/"); - strcat(tmp2, PROGRAM); - testprogfile = tmp2; - } - - { - char *testprg; -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Command.com sometimes rejects '/' separators. */ - testprg = strdup(testprogfile); - for (i = 0; testprg[i] != '\0'; i++) { - if (testprg[i] == '/') - testprg[i] = '\\'; - } - testprogfile = testprg; -#endif - /* Quote the name that gets put into shell command lines. */ - testprg = malloc(strlen(testprogfile) + 3); - strcpy(testprg, "\""); - strcat(testprg, testprogfile); - strcat(testprg, "\""); - testprog = testprg; - } -#endif - -#if !defined(_WIN32) && defined(SIGPIPE) - { /* Ignore SIGPIPE signals */ - struct sigaction sa; - sa.sa_handler = SIG_IGN; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGPIPE, &sa, NULL); - } -#endif - - /* - * Create a temp directory for the following tests. - * Include the time the tests started as part of the name, - * to make it easier to track the results of multiple tests. - */ - now = time(NULL); - for (i = 0; ; i++) { - strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp), - "%Y-%m-%dT%H.%M.%S", - localtime(&now)); - sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname, - tmpdir_timestamp, i); - if (assertMakeDir(tmpdir,0755)) - break; - if (i >= 999) { - fprintf(stderr, - "ERROR: Unable to create temp directory %s\n", - tmpdir); - exit(1); - } - } - - /* - * If the user didn't specify a directory for locating - * reference files, try to find the reference files in - * the "usual places." - */ - refdir = refdir_alloc = get_refdir(refdir); - - /* - * Banner with basic information. - */ - printf("\n"); - printf("If tests fail or crash, details will be in:\n"); - printf(" %s\n", tmpdir); - printf("\n"); - if (verbosity > VERBOSITY_SUMMARY_ONLY) { - printf("Reference files will be read from: %s\n", refdir); -#ifdef PROGRAM - printf("Running tests on: %s\n", testprog); -#endif - printf("Exercising: "); - fflush(stdout); - printf("%s\n", EXTRA_VERSION); - } else { - printf("Running "); - fflush(stdout); - } - - /* - * Run some or all of the individual tests. - */ - saved_argv = argv; - do { - argv = saved_argv; - do { - int test_num; - - test_num = get_test_set(test_set, limit, *argv, tests); - if (test_num < 0) { - printf("*** INVALID Test %s\n", *argv); - free(refdir_alloc); - free(testprogdir); - usage(progname); - return (1); - } - for (i = 0; i < test_num; i++) { - tests_run++; - if (test_run(test_set[i], tmpdir)) { - tests_failed++; - if (until_failure) - goto finish; - } - } - if (*argv != NULL) - argv++; - } while (*argv != NULL); - } while (until_failure); - -finish: - /* Must be freed after all tests run */ - free(tmp2); - free(testprogdir); - free(pwd); - - /* - * Report summary statistics. - */ - if (verbosity > VERBOSITY_SUMMARY_ONLY) { - printf("\n"); - printf("Totals:\n"); - printf(" Tests run: %8d\n", tests_run); - printf(" Tests failed: %8d\n", tests_failed); - printf(" Assertions checked:%8d\n", assertions); - printf(" Assertions failed: %8d\n", failures); - printf(" Skips reported: %8d\n", skips); - } - if (failures) { - printf("\n"); - printf("Failing tests:\n"); - for (i = 0; i < limit; ++i) { - if (tests[i].failures) - printf(" %d: %s (%d failures)\n", i, - tests[i].name, tests[i].failures); - } - printf("\n"); - printf("Details for failing tests: %s\n", tmpdir); - printf("\n"); - } else { - if (verbosity == VERBOSITY_SUMMARY_ONLY) - printf("\n"); - printf("%d tests passed, no failures\n", tests_run); - } - - free(refdir_alloc); - - /* If the final tmpdir is empty, we can remove it. */ - /* This should be the usual case when all tests succeed. */ - assertChdir(".."); - rmdir(tmpdir); - - return (tests_failed ? 1 : 0); -} diff --git a/cpio/test/test.h b/cpio/test/test.h index 49fa32c9..1dadf688 100644 --- a/cpio/test/test.h +++ b/cpio/test/test.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2006 Tim Kientzle + * Copyright (c) 2003-2017 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,333 +22,19 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/usr.bin/cpio/test/test.h,v 1.2 2008/06/21 02:17:18 kientzle Exp $ + * $FreeBSD$ */ /* Every test program should #include "test.h" as the first thing. */ -/* - * The goal of this file (and the matching test.c) is to - * simplify the very repetitive test-*.c test programs. - */ -#if defined(HAVE_CONFIG_H) -/* Most POSIX platforms use the 'configure' script to build config.h */ -#include "config.h" -#elif defined(__FreeBSD__) -/* Building as part of FreeBSD system requires a pre-built config.h. */ -#include "config_freebsd.h" -#elif defined(_WIN32) && !defined(__CYGWIN__) -/* Win32 can't run the 'configure' script. */ -#include "config_windows.h" -#else -/* Warn if the library hasn't been (automatically or manually) configured. */ -#error Oops: No config.h and no pre-built configuration in test.h. -#endif - -#include <sys/types.h> /* Windows requires this before sys/stat.h */ -#include <sys/stat.h> - -#if HAVE_DIRENT_H -#include <dirent.h> -#endif -#ifdef HAVE_DIRECT_H -#include <direct.h> -#define dirent direct -#endif -#include <errno.h> -#include <fcntl.h> -#ifdef HAVE_IO_H -#include <io.h> -#endif -#ifdef HAVE_STDINT_H -#include <stdint.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <time.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <wchar.h> -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif - -/* - * System-specific tweaks. We really want to minimize these - * as much as possible, since they make it harder to understand - * the mainline code. - */ - -/* Windows (including Visual Studio and MinGW but not Cygwin) */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#if !defined(__BORLANDC__) -#undef chdir -#define chdir _chdir -#define strdup _strdup -#endif -#endif - -/* Visual Studio */ -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf sprintf_s -#endif - -#if defined(__BORLANDC__) -#pragma warn -8068 /* Constant out of range in comparison. */ -#endif - -/* Haiku OS and QNX */ -#if defined(__HAIKU__) || defined(__QNXNTO__) -/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */ -#include <stdint.h> -#endif - -/* Get a real definition for __FBSDID if we can */ -#if HAVE_SYS_CDEFS_H -#include <sys/cdefs.h> -#endif - -/* If not, define it so as to avoid dangling semicolons. */ -#ifndef __FBSDID -#define __FBSDID(a) struct _undefined_hack -#endif - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -/* - * Redefine DEFINE_TEST for use in defining the test functions. - */ -#undef DEFINE_TEST -#define DEFINE_TEST(name) void name(void); void name(void) - -/* An implementation of the standard assert() macro */ -#define assert(e) assertion_assert(__FILE__, __LINE__, (e), #e, NULL) -/* chdir() and error if it fails */ -#define assertChdir(path) \ - assertion_chdir(__FILE__, __LINE__, path) -/* Assert two integers are the same. Reports value of each one if not. */ -#define assertEqualInt(v1,v2) \ - assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) -/* Assert two strings are the same. Reports value of each one if not. */ -#define assertEqualString(v1,v2) \ - assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0) -#define assertEqualUTF8String(v1,v2) \ - assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1) -/* As above, but v1 and v2 are wchar_t * */ -#define assertEqualWString(v1,v2) \ - assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) -/* As above, but raw blocks of bytes. */ -#define assertEqualMem(v1, v2, l) \ - assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL) -/* Assert that memory is full of a specified byte */ -#define assertMemoryFilledWith(v1, l, b) \ - assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL) -/* Assert two files are the same. */ -#define assertEqualFile(f1, f2) \ - assertion_equal_file(__FILE__, __LINE__, (f1), (f2)) -/* Assert that a file is empty. */ -#define assertEmptyFile(pathname) \ - assertion_empty_file(__FILE__, __LINE__, (pathname)) -/* Assert that a file is not empty. */ -#define assertNonEmptyFile(pathname) \ - assertion_non_empty_file(__FILE__, __LINE__, (pathname)) -#define assertFileAtime(pathname, sec, nsec) \ - assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileAtimeRecent(pathname) \ - assertion_file_atime_recent(__FILE__, __LINE__, pathname) -#define assertFileBirthtime(pathname, sec, nsec) \ - assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileBirthtimeRecent(pathname) \ - assertion_file_birthtime_recent(__FILE__, __LINE__, pathname) -/* Assert that a file exists; supports printf-style arguments. */ -#define assertFileExists(pathname) \ - assertion_file_exists(__FILE__, __LINE__, pathname) -/* Assert that a file exists. */ -#define assertFileNotExists(pathname) \ - assertion_file_not_exists(__FILE__, __LINE__, pathname) -/* Assert that file contents match a string. */ -#define assertFileContents(data, data_size, pathname) \ - assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname) -/* Verify that a file does not contain invalid strings */ -#define assertFileContainsNoInvalidStrings(pathname, strings) \ - assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings) -#define assertFileMtime(pathname, sec, nsec) \ - assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileMtimeRecent(pathname) \ - assertion_file_mtime_recent(__FILE__, __LINE__, pathname) -#define assertFileNLinks(pathname, nlinks) \ - assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks) -#define assertFileSize(pathname, size) \ - assertion_file_size(__FILE__, __LINE__, pathname, size) -#define assertFileMode(pathname, mode) \ - assertion_file_mode(__FILE__, __LINE__, pathname, mode) -#define assertTextFileContents(text, pathname) \ - assertion_text_file_contents(__FILE__, __LINE__, text, pathname) -#define assertFileContainsLinesAnyOrder(pathname, lines) \ - assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines) -#define assertIsDir(pathname, mode) \ - assertion_is_dir(__FILE__, __LINE__, pathname, mode) -#define assertIsHardlink(path1, path2) \ - assertion_is_hardlink(__FILE__, __LINE__, path1, path2) -#define assertIsNotHardlink(path1, path2) \ - assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2) -#define assertIsReg(pathname, mode) \ - assertion_is_reg(__FILE__, __LINE__, pathname, mode) -#define assertIsSymlink(pathname, contents) \ - assertion_is_symlink(__FILE__, __LINE__, pathname, contents) -/* Create a directory, report error if it fails. */ -#define assertMakeDir(dirname, mode) \ - assertion_make_dir(__FILE__, __LINE__, dirname, mode) -#define assertMakeFile(path, mode, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents) -#define assertMakeBinFile(path, mode, csize, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents) -#define assertMakeHardlink(newfile, oldfile) \ - assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) -#define assertMakeSymlink(newfile, linkto) \ - assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) -#define assertNodump(path) \ - assertion_nodump(__FILE__, __LINE__, path) -#define assertUmask(mask) \ - assertion_umask(__FILE__, __LINE__, mask) -#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \ - assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec) - -/* - * This would be simple with C99 variadic macros, but I don't want to - * require that. Instead, I insert a function call before each - * skipping() call to pass the file and line information down. Crude, - * but effective. - */ -#define skipping \ - skipping_setup(__FILE__, __LINE__);test_skipping - -/* Function declarations. These are defined in test_utility.c. */ -void failure(const char *fmt, ...); -int assertion_assert(const char *, int, int, const char *, void *); -int assertion_chdir(const char *, int, const char *); -int assertion_empty_file(const char *, int, const char *); -int assertion_equal_file(const char *, int, const char *, const char *); -int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *); -int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *); -int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *); -int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int); -int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); -int assertion_file_atime(const char *, int, const char *, long, long); -int assertion_file_atime_recent(const char *, int, const char *); -int assertion_file_birthtime(const char *, int, const char *, long, long); -int assertion_file_birthtime_recent(const char *, int, const char *); -int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **); -int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **); -int assertion_file_contents(const char *, int, const void *, int, const char *); -int assertion_file_exists(const char *, int, const char *); -int assertion_file_mode(const char *, int, const char *, int); -int assertion_file_mtime(const char *, int, const char *, long, long); -int assertion_file_mtime_recent(const char *, int, const char *); -int assertion_file_nlinks(const char *, int, const char *, int); -int assertion_file_not_exists(const char *, int, const char *); -int assertion_file_size(const char *, int, const char *, long); -int assertion_is_dir(const char *, int, const char *, int); -int assertion_is_hardlink(const char *, int, const char *, const char *); -int assertion_is_not_hardlink(const char *, int, const char *, const char *); -int assertion_is_reg(const char *, int, const char *, int); -int assertion_is_symlink(const char *, int, const char *, const char *); -int assertion_make_dir(const char *, int, const char *, int); -int assertion_make_file(const char *, int, const char *, int, int, const void *); -int assertion_make_hardlink(const char *, int, const char *newpath, const char *); -int assertion_make_symlink(const char *, int, const char *newpath, const char *); -int assertion_nodump(const char *, int, const char *); -int assertion_non_empty_file(const char *, int, const char *); -int assertion_text_file_contents(const char *, int, const char *buff, const char *f); -int assertion_umask(const char *, int, int); -int assertion_utimes(const char *, int, const char *, long, long, long, long ); - -void skipping_setup(const char *, int); -void test_skipping(const char *fmt, ...); - -/* Like sprintf, then system() */ -int systemf(const char * fmt, ...); - -/* Delay until time() returns a value after this. */ -void sleepUntilAfter(time_t); - -/* Return true if this platform can create symlinks. */ -int canSymlink(void); - -/* Return true if this platform can run the "bzip2" program. */ -int canBzip2(void); - -/* Return true if this platform can run the "grzip" program. */ -int canGrzip(void); - -/* Return true if this platform can run the "gzip" program. */ -int canGzip(void); - -/* Return true if this platform can run the specified command. */ -int canRunCommand(const char *); - -/* Return true if this platform can run the "lrzip" program. */ -int canLrzip(void); - -/* Return true if this platform can run the "lz4" program. */ -int canLz4(void); - -/* Return true if this platform can run the "lzip" program. */ -int canLzip(void); - -/* Return true if this platform can run the "lzma" program. */ -int canLzma(void); - -/* Return true if this platform can run the "lzop" program. */ -int canLzop(void); - -/* Return true if this platform can run the "xz" program. */ -int canXz(void); - -/* Return true if this filesystem can handle nodump flags. */ -int canNodump(void); - -/* Return true if the file has large i-node number(>0xffffffff). */ -int is_LargeInode(const char *); - -/* Suck file into string allocated via malloc(). Call free() when done. */ -/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */ -char *slurpfile(size_t *, const char *fmt, ...); - -/* Dump block of bytes to a file. */ -void dumpfile(const char *filename, void *, size_t); - -/* Extracts named reference file to the current directory. */ -void extract_reference_file(const char *); -/* Copies named reference file to the current directory. */ -void copy_reference_file(const char *); - -/* Extracts a list of files to the current directory. - * List must be NULL terminated. - */ -void extract_reference_files(const char **); - -/* Subtract umask from mode */ -mode_t umasked(mode_t expected_mode); - -/* Path to working directory for current test */ -extern const char *testworkdir; - -/* - * Special interfaces for program test harness. - */ - -/* Pathname of exe to be tested. */ -extern const char *testprogfile; -/* Name of exe to use in printf-formatted command strings. */ -/* On Windows, this includes leading/trailing quotes. */ -extern const char *testprog; - -#ifdef USE_DMALLOC -#include <dmalloc.h> -#endif +#define KNOWNREF "test_option_f.cpio.uu" +#define ENVBASE "BSDCPIO" /* Prefix for environment variables. */ +#define PROGRAM "bsdcpio" /* Name of program being tested. */ +#define PROGRAM_ALIAS "cpio" /* Generic alias for program */ +#undef LIBRARY /* Not testing a library. */ +#undef EXTRA_DUMP /* How to dump extra data */ +#undef EXTRA_ERRNO /* How to dump errno */ +/* How to generate extra version info. */ +#define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") + +#include "test_common.h" diff --git a/cpio/test/test_option_version.c b/cpio/test/test_option_version.c index 78ac2180..505db271 100644 --- a/cpio/test/test_option_version.c +++ b/cpio/test/test_option_version.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2003-2017 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,9 +23,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -__FBSDID("$FreeBSD$"); - -#include "lib/version.h" DEFINE_TEST(test_option_version) { diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index 694d8829..5016eed3 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -6,8 +6,7 @@ IF(ENABLE_TEST) SET(libarchive_test_SOURCES ../../test_utils/test_utils.c - ../../test_utils/lib/version.c - main.c + ../../test_utils/test_main.c read_open_memory.c test.h test_acl_nfs4.c @@ -304,6 +303,7 @@ IF(ENABLE_TEST) INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/libarchive/test) # Experimental new test handling ADD_CUSTOM_TARGET(run_libarchive_test diff --git a/libarchive/test/test.h b/libarchive/test/test.h index 58df1cbf..fd679f5f 100644 --- a/libarchive/test/test.h +++ b/libarchive/test/test.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2006 Tim Kientzle + * Copyright (c) 2003-2017 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,388 +21,16 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/lib/libarchive/test/test.h 201247 2009-12-30 05:59:21Z kientzle $ */ /* Every test program should #include "test.h" as the first thing. */ -/* - * The goal of this file (and the matching test.c) is to - * simplify the very repetitive test-*.c test programs. - */ -#if defined(HAVE_CONFIG_H) -/* Most POSIX platforms use the 'configure' script to build config.h */ -#include "config.h" -#elif defined(__FreeBSD__) -/* Building as part of FreeBSD system requires a pre-built config.h. */ -#include "config_freebsd.h" -#elif defined(_WIN32) && !defined(__CYGWIN__) -/* Win32 can't run the 'configure' script. */ -#include "config_windows.h" -#else -/* Warn if the library hasn't been (automatically or manually) configured. */ -#error Oops: No config.h and no pre-built configuration in test.h. -#endif - -#include <sys/types.h> /* Windows requires this before sys/stat.h */ -#include <sys/stat.h> - -#if HAVE_DIRENT_H -#include <dirent.h> -#endif -#ifdef HAVE_DIRECT_H -#include <direct.h> -#define dirent direct -#endif -#include <errno.h> -#include <fcntl.h> -#ifdef HAVE_IO_H -#include <io.h> -#endif -#ifdef HAVE_STDINT_H -#include <stdint.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <time.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <wchar.h> -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif - -/* - * System-specific tweaks. We really want to minimize these - * as much as possible, since they make it harder to understand - * the mainline code. - */ - -/* Windows (including Visual Studio and MinGW but not Cygwin) */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#if !defined(__BORLANDC__) -#undef chdir -#define chdir _chdir -#define strdup _strdup -#endif -#endif - -/* Visual Studio */ -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf sprintf_s -#endif - -#if defined(__BORLANDC__) -#pragma warn -8068 /* Constant out of range in comparison. */ -#endif - -/* Haiku OS and QNX */ -#if defined(__HAIKU__) || defined(__QNXNTO__) -/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */ -#include <stdint.h> -#endif - -/* Get a real definition for __FBSDID if we can */ -#if HAVE_SYS_CDEFS_H -#include <sys/cdefs.h> -#endif - -/* If not, define it so as to avoid dangling semicolons. */ -#ifndef __FBSDID -#define __FBSDID(a) struct _undefined_hack -#endif - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -/* - * If this platform has <sys/acl.h>, acl_create(), acl_init(), - * acl_set_file(), and ACL_USER, we assume it has the rest of the - * POSIX.1e draft functions used in archive_read_extract.c. - */ -#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE -#if HAVE_ACL_USER -#define HAVE_POSIX_ACL 1 -#elif HAVE_ACL_TYPE_EXTENDED -#define HAVE_DARWIN_ACL 1 -#endif -#endif - -/* - * If this platform has <sys/acl.h>, acl_get(), facl_get(), acl_set(), - * facl_set() and types aclent_t and ace_t it uses Solaris-style ACL functions - */ -#if HAVE_SYS_ACL_H && HAVE_ACL_GET && HAVE_FACL_GET && HAVE_ACL_SET && HAVE_FACL_SET && HAVE_ACLENT_T && HAVE_ACE_T -#define HAVE_SUN_ACL 1 -#endif - -/* Define if platform supports NFSv4 ACLs */ -#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL -#define HAVE_NFS4_ACL 1 -#endif - -/* - * Redefine DEFINE_TEST for use in defining the test functions. - */ -#undef DEFINE_TEST -#define DEFINE_TEST(name) void name(void); void name(void) - -/* An implementation of the standard assert() macro */ -#define assert(e) assertion_assert(__FILE__, __LINE__, (e), #e, NULL) -/* chdir() and error if it fails */ -#define assertChdir(path) \ - assertion_chdir(__FILE__, __LINE__, path) -/* Assert two integers are the same. Reports value of each one if not. */ -#define assertEqualInt(v1,v2) \ - assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) -/* Assert two strings are the same. Reports value of each one if not. */ -#define assertEqualString(v1,v2) \ - assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0) -#define assertEqualUTF8String(v1,v2) \ - assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1) -/* As above, but v1 and v2 are wchar_t * */ -#define assertEqualWString(v1,v2) \ - assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) -/* As above, but raw blocks of bytes. */ -#define assertEqualMem(v1, v2, l) \ - assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL) -/* Assert that memory is full of a specified byte */ -#define assertMemoryFilledWith(v1, l, b) \ - assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL) -/* Assert two files are the same. */ -#define assertEqualFile(f1, f2) \ - assertion_equal_file(__FILE__, __LINE__, (f1), (f2)) -/* Assert that a file is empty. */ -#define assertEmptyFile(pathname) \ - assertion_empty_file(__FILE__, __LINE__, (pathname)) -/* Assert that a file is not empty. */ -#define assertNonEmptyFile(pathname) \ - assertion_non_empty_file(__FILE__, __LINE__, (pathname)) -#define assertFileAtime(pathname, sec, nsec) \ - assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileAtimeRecent(pathname) \ - assertion_file_atime_recent(__FILE__, __LINE__, pathname) -#define assertFileBirthtime(pathname, sec, nsec) \ - assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileBirthtimeRecent(pathname) \ - assertion_file_birthtime_recent(__FILE__, __LINE__, pathname) -/* Assert that a file exists; supports printf-style arguments. */ -#define assertFileExists(pathname) \ - assertion_file_exists(__FILE__, __LINE__, pathname) -/* Assert that a file exists. */ -#define assertFileNotExists(pathname) \ - assertion_file_not_exists(__FILE__, __LINE__, pathname) -/* Assert that file contents match a string. */ -#define assertFileContents(data, data_size, pathname) \ - assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname) -/* Verify that a file does not contain invalid strings */ -#define assertFileContainsNoInvalidStrings(pathname, strings) \ - assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings) -#define assertFileMtime(pathname, sec, nsec) \ - assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileMtimeRecent(pathname) \ - assertion_file_mtime_recent(__FILE__, __LINE__, pathname) -#define assertFileNLinks(pathname, nlinks) \ - assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks) -#define assertFileSize(pathname, size) \ - assertion_file_size(__FILE__, __LINE__, pathname, size) -#define assertFileMode(pathname, mode) \ - assertion_file_mode(__FILE__, __LINE__, pathname, mode) -#define assertTextFileContents(text, pathname) \ - assertion_text_file_contents(__FILE__, __LINE__, text, pathname) -#define assertFileContainsLinesAnyOrder(pathname, lines) \ - assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines) -#define assertIsDir(pathname, mode) \ - assertion_is_dir(__FILE__, __LINE__, pathname, mode) -#define assertIsHardlink(path1, path2) \ - assertion_is_hardlink(__FILE__, __LINE__, path1, path2) -#define assertIsNotHardlink(path1, path2) \ - assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2) -#define assertIsReg(pathname, mode) \ - assertion_is_reg(__FILE__, __LINE__, pathname, mode) -#define assertIsSymlink(pathname, contents) \ - assertion_is_symlink(__FILE__, __LINE__, pathname, contents) -/* Create a directory, report error if it fails. */ -#define assertMakeDir(dirname, mode) \ - assertion_make_dir(__FILE__, __LINE__, dirname, mode) -#define assertMakeFile(path, mode, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents) -#define assertMakeBinFile(path, mode, csize, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents) -#define assertMakeHardlink(newfile, oldfile) \ - assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) -#define assertMakeSymlink(newfile, linkto) \ - assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) -#define assertNodump(path) \ - assertion_nodump(__FILE__, __LINE__, path) -#define assertUmask(mask) \ - assertion_umask(__FILE__, __LINE__, mask) -#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \ - assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec) - -/* - * This would be simple with C99 variadic macros, but I don't want to - * require that. Instead, I insert a function call before each - * skipping() call to pass the file and line information down. Crude, - * but effective. - */ -#define skipping \ - skipping_setup(__FILE__, __LINE__);test_skipping - -/* Function declarations. These are defined in test_utility.c. */ -void failure(const char *fmt, ...); -int assertion_assert(const char *, int, int, const char *, void *); -int assertion_chdir(const char *, int, const char *); -int assertion_empty_file(const char *, int, const char *); -int assertion_equal_file(const char *, int, const char *, const char *); -int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *); -int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *); -int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *); -int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int); -int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); -int assertion_file_atime(const char *, int, const char *, long, long); -int assertion_file_atime_recent(const char *, int, const char *); -int assertion_file_birthtime(const char *, int, const char *, long, long); -int assertion_file_birthtime_recent(const char *, int, const char *); -int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **); -int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **); -int assertion_file_contents(const char *, int, const void *, int, const char *); -int assertion_file_exists(const char *, int, const char *); -int assertion_file_mode(const char *, int, const char *, int); -int assertion_file_mtime(const char *, int, const char *, long, long); -int assertion_file_mtime_recent(const char *, int, const char *); -int assertion_file_nlinks(const char *, int, const char *, int); -int assertion_file_not_exists(const char *, int, const char *); -int assertion_file_size(const char *, int, const char *, long); -int assertion_is_dir(const char *, int, const char *, int); -int assertion_is_hardlink(const char *, int, const char *, const char *); -int assertion_is_not_hardlink(const char *, int, const char *, const char *); -int assertion_is_reg(const char *, int, const char *, int); -int assertion_is_symlink(const char *, int, const char *, const char *); -int assertion_make_dir(const char *, int, const char *, int); -int assertion_make_file(const char *, int, const char *, int, int, const void *); -int assertion_make_hardlink(const char *, int, const char *newpath, const char *); -int assertion_make_symlink(const char *, int, const char *newpath, const char *); -int assertion_nodump(const char *, int, const char *); -int assertion_non_empty_file(const char *, int, const char *); -int assertion_text_file_contents(const char *, int, const char *buff, const char *f); -int assertion_umask(const char *, int, int); -int assertion_utimes(const char *, int, const char *, long, long, long, long ); - -void skipping_setup(const char *, int); -void test_skipping(const char *fmt, ...); - -/* Like sprintf, then system() */ -int systemf(const char * fmt, ...); - -/* Delay until time() returns a value after this. */ -void sleepUntilAfter(time_t); - -/* Return true if this platform can create symlinks. */ -int canSymlink(void); - -/* Return true if this platform can run the "bzip2" program. */ -int canBzip2(void); - -/* Return true if this platform can run the "grzip" program. */ -int canGrzip(void); - -/* Return true if this platform can run the "gzip" program. */ -int canGzip(void); - -/* Return true if this platform can run the specified command. */ -int canRunCommand(const char *); - -/* Return true if this platform can run the "lrzip" program. */ -int canLrzip(void); - -/* Return true if this platform can run the "lz4" program. */ -int canLz4(void); - -/* Return true if this platform can run the "lzip" program. */ -int canLzip(void); - -/* Return true if this platform can run the "lzma" program. */ -int canLzma(void); - -/* Return true if this platform can run the "lzop" program. */ -int canLzop(void); - -/* Return true if this platform can run the "xz" program. */ -int canXz(void); - -/* Return true if this filesystem can handle nodump flags. */ -int canNodump(void); - -/* Return true if the file has large i-node number(>0xffffffff). */ -int is_LargeInode(const char *); - -/* Suck file into string allocated via malloc(). Call free() when done. */ -/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */ -char *slurpfile(size_t *, const char *fmt, ...); - -/* Dump block of bytes to a file. */ -void dumpfile(const char *filename, void *, size_t); - -/* Extracts named reference file to the current directory. */ -void extract_reference_file(const char *); -/* Copies named reference file to the current directory. */ -void copy_reference_file(const char *); - -/* Extracts a list of files to the current directory. - * List must be NULL terminated. - */ -void extract_reference_files(const char **); - -/* Subtract umask from mode */ -mode_t umasked(mode_t expected_mode); - -/* Path to working directory for current test */ -extern const char *testworkdir; - -/* - * Special interfaces for libarchive test harness. - */ - -#include "archive.h" -#include "archive_entry.h" - -/* ACL structure */ -struct archive_test_acl_t { - int type; /* Type of ACL */ - int permset; /* Permissions for this class of users. */ - int tag; /* Owner, User, Owning group, group, other, etc. */ - int qual; /* GID or UID of user/group, depending on tag. */ - const char *name; /* Name of user/group, depending on tag. */ -}; - -/* Set ACLs */ -void archive_test_set_acls(struct archive_entry *, struct archive_test_acl_t *, - int); - -/* Compare ACLs */ -void archive_test_compare_acls(struct archive_entry *, - struct archive_test_acl_t *, int, int, int); - -/* Special customized read-from-memory interface. */ -int read_open_memory(struct archive *, const void *, size_t, size_t); -/* _minimal version exercises a slightly different set of libarchive APIs. */ -int read_open_memory_minimal(struct archive *, const void *, size_t, size_t); -/* _seek version produces a seekable file. */ -int read_open_memory_seek(struct archive *, const void *, size_t, size_t); - -/* Versions of above that accept an archive argument for additional info. */ -#define assertA(e) assertion_assert(__FILE__, __LINE__, (e), #e, (a)) -#define assertEqualIntA(a,v1,v2) \ - assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a)) -#define assertEqualStringA(a,v1,v2) \ - assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a), 0) +#define KNOWNREF "test_compat_gtar_1.tar.uu" +#define ENVBASE "LIBARCHIVE" /* Prefix for environment variables. */ +#undef PROGRAM /* Testing a library, not a program. */ +#define LIBRARY "libarchive" +#define EXTRA_DUMP(x) archive_error_string((struct archive *)(x)) +#define EXTRA_ERRNO(x) archive_errno((struct archive *)(x)) +#define EXTRA_VERSION archive_version_details() -#ifdef USE_DMALLOC -#include <dmalloc.h> -#endif +#include "test_common.h" diff --git a/tar/test/CMakeLists.txt b/tar/test/CMakeLists.txt index 6f6fc215..3dd36019 100644 --- a/tar/test/CMakeLists.txt +++ b/tar/test/CMakeLists.txt @@ -6,8 +6,7 @@ IF(ENABLE_TAR AND ENABLE_TEST) SET(bsdtar_test_SOURCES ../../test_utils/test_utils.c - ../../test_utils/lib/version.c - main.c + ../../test_utils/test_main.c test.h test_0.c test_basic.c @@ -97,6 +96,7 @@ IF(ENABLE_TAR AND ENABLE_TEST) INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/tar/test) # Experimental new test handling ADD_CUSTOM_TARGET(run_bsdtar_test diff --git a/tar/test/main.c b/tar/test/main.c deleted file mode 100644 index 8d31706f..00000000 --- a/tar/test/main.c +++ /dev/null @@ -1,3072 +0,0 @@ -/* - * Copyright (c) 2003-2009 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "test.h" -#include "test_utils.h" -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#include <errno.h> -#ifdef HAVE_ICONV_H -#include <iconv.h> -#endif -/* - * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. - * As the include guards don't agree, the order of include is important. - */ -#ifdef HAVE_LINUX_EXT2_FS_H -#include <linux/ext2_fs.h> /* for Linux file flags */ -#endif -#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) -#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ -#endif -#include <limits.h> -#include <locale.h> -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#include <stdarg.h> -#include <time.h> - -/* - * This same file is used pretty much verbatim for all test harnesses. - * - * The next few lines are the only differences. - * TODO: Move this into a separate configuration header, have all test - * suites share one copy of this file. - */ -__FBSDID("$FreeBSD: src/usr.bin/tar/test/main.c,v 1.6 2008/11/05 06:40:53 kientzle Exp $"); -#define KNOWNREF "test_patterns_2.tar.uu" -#define ENVBASE "BSDTAR" /* Prefix for environment variables. */ -#define PROGRAM "bsdtar" /* Name of program being tested. */ -#define PROGRAM_ALIAS "tar" /* Generic alias for program */ -#undef LIBRARY /* Not testing a library. */ -#undef EXTRA_DUMP /* How to dump extra data */ -#undef EXTRA_ERRNO /* How to dump errno */ -/* How to generate extra version info. */ -#define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") - -/* - * - * Windows support routines - * - * Note: Configuration is a tricky issue. Using HAVE_* feature macros - * in the test harness is dangerous because they cover up - * configuration errors. The classic example of this is omitting a - * configure check. If libarchive and libarchive_test both look for - * the same feature macro, such errors are hard to detect. Platform - * macros (e.g., _WIN32 or __GNUC__) are a little better, but can - * easily lead to very messy code. It's best to limit yourself - * to only the most generic programming techniques in the test harness - * and thus avoid conditionals altogether. Where that's not possible, - * try to minimize conditionals by grouping platform-specific tests in - * one place (e.g., test_acl_freebsd) or by adding new assert() - * functions (e.g., assertMakeHardlink()) to cover up platform - * differences. Platform-specific coding in libarchive_test is often - * a symptom that some capability is missing from libarchive itself. - */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#include <io.h> -#include <direct.h> -#include <windows.h> -#ifndef F_OK -#define F_OK (0) -#endif -#ifndef S_ISDIR -#define S_ISDIR(m) ((m) & _S_IFDIR) -#endif -#ifndef S_ISREG -#define S_ISREG(m) ((m) & _S_IFREG) -#endif -#if !defined(__BORLANDC__) -#define access _access -#undef chdir -#define chdir _chdir -#endif -#ifndef fileno -#define fileno _fileno -#endif -/*#define fstat _fstat64*/ -#if !defined(__BORLANDC__) -#define getcwd _getcwd -#endif -#define lstat stat -/*#define lstat _stat64*/ -/*#define stat _stat64*/ -#define rmdir _rmdir -#if !defined(__BORLANDC__) -#define strdup _strdup -#define umask _umask -#endif -#define int64_t __int64 -#endif - -#if defined(HAVE__CrtSetReportMode) -# include <crtdbg.h> -#endif - -mode_t umasked(mode_t expected_mode) -{ - mode_t mode = umask(0); - umask(mode); - return expected_mode & ~mode; -} - -/* Path to working directory for current test */ -const char *testworkdir; -#ifdef PROGRAM -/* Pathname of exe to be tested. */ -const char *testprogfile; -/* Name of exe to use in printf-formatted command strings. */ -/* On Windows, this includes leading/trailing quotes. */ -const char *testprog; -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) -static void *GetFunctionKernel32(const char *); -static int my_CreateSymbolicLinkA(const char *, const char *, int); -static int my_CreateHardLinkA(const char *, const char *); -static int my_GetFileInformationByName(const char *, - BY_HANDLE_FILE_INFORMATION *); - -static void * -GetFunctionKernel32(const char *name) -{ - static HINSTANCE lib; - static int set; - if (!set) { - set = 1; - lib = LoadLibrary("kernel32.dll"); - } - if (lib == NULL) { - fprintf(stderr, "Can't load kernel32.dll?!\n"); - exit(1); - } - return (void *)GetProcAddress(lib, name); -} - -static int -my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags) -{ - static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD); - static int set; - if (!set) { - set = 1; - f = GetFunctionKernel32("CreateSymbolicLinkA"); - } - return f == NULL ? 0 : (*f)(linkname, target, flags); -} - -static int -my_CreateHardLinkA(const char *linkname, const char *target) -{ - static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); - static int set; - if (!set) { - set = 1; - f = GetFunctionKernel32("CreateHardLinkA"); - } - return f == NULL ? 0 : (*f)(linkname, target, NULL); -} - -static int -my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) -{ - HANDLE h; - int r; - - memset(bhfi, 0, sizeof(*bhfi)); - h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) - return (0); - r = GetFileInformationByHandle(h, bhfi); - CloseHandle(h); - return (r); -} -#endif - -#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__) -static void -invalid_parameter_handler(const wchar_t * expression, - const wchar_t * function, const wchar_t * file, - unsigned int line, uintptr_t pReserved) -{ - /* nop */ -} -#endif - -/* - * - * OPTIONS FLAGS - * - */ - -/* Enable core dump on failure. */ -static int dump_on_failure = 0; -/* Default is to remove temp dirs and log data for successful tests. */ -static int keep_temp_files = 0; -/* Default is to run the specified tests once and report errors. */ -static int until_failure = 0; -/* Default is to just report pass/fail for each test. */ -static int verbosity = 0; -#define VERBOSITY_SUMMARY_ONLY -1 /* -q */ -#define VERBOSITY_PASSFAIL 0 /* Default */ -#define VERBOSITY_LIGHT_REPORT 1 /* -v */ -#define VERBOSITY_FULL 2 /* -vv */ -/* A few places generate even more output for verbosity > VERBOSITY_FULL, - * mostly for debugging the test harness itself. */ -/* Cumulative count of assertion failures. */ -static int failures = 0; -/* Cumulative count of reported skips. */ -static int skips = 0; -/* Cumulative count of assertions checked. */ -static int assertions = 0; - -/* Directory where uuencoded reference files can be found. */ -static const char *refdir; - -/* - * Report log information selectively to console and/or disk log. - */ -static int log_console = 0; -static FILE *logfile; -static void -vlogprintf(const char *fmt, va_list ap) -{ -#ifdef va_copy - va_list lfap; - va_copy(lfap, ap); -#endif - if (log_console) - vfprintf(stdout, fmt, ap); - if (logfile != NULL) -#ifdef va_copy - vfprintf(logfile, fmt, lfap); - va_end(lfap); -#else - vfprintf(logfile, fmt, ap); -#endif -} - -static void -logprintf(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vlogprintf(fmt, ap); - va_end(ap); -} - -/* Set up a message to display only if next assertion fails. */ -static char msgbuff[4096]; -static const char *msg, *nextmsg; -void -failure(const char *fmt, ...) -{ - va_list ap; - if (fmt == NULL) { - nextmsg = NULL; - } else { - va_start(ap, fmt); - vsprintf(msgbuff, fmt, ap); - va_end(ap); - nextmsg = msgbuff; - } -} - -/* - * Copy arguments into file-local variables. - * This was added to permit vararg assert() functions without needing - * variadic wrapper macros. Turns out that the vararg capability is almost - * never used, so almost all of the vararg assertions can be simplified - * by removing the vararg capability and reworking the wrapper macro to - * pass __FILE__, __LINE__ directly into the function instead of using - * this hook. I suspect this machinery is used so rarely that we - * would be better off just removing it entirely. That would simplify - * the code here noticeably. - */ -static const char *skipping_filename; -static int skipping_line; -void skipping_setup(const char *filename, int line) -{ - skipping_filename = filename; - skipping_line = line; -} - -/* Called at the beginning of each assert() function. */ -static void -assertion_count(const char *file, int line) -{ - (void)file; /* UNUSED */ - (void)line; /* UNUSED */ - ++assertions; - /* Proper handling of "failure()" message. */ - msg = nextmsg; - nextmsg = NULL; - /* Uncomment to print file:line after every assertion. - * Verbose, but occasionally useful in tracking down crashes. */ - /* printf("Checked %s:%d\n", file, line); */ -} - -/* - * For each test source file, we remember how many times each - * assertion was reported. Cleared before each new test, - * used by test_summarize(). - */ -static struct line { - int count; - int skip; -} failed_lines[10000]; -const char *failed_filename; - -/* Count this failure, setup up log destination and handle initial report. */ -static void -failure_start(const char *filename, int line, const char *fmt, ...) -{ - va_list ap; - - /* Record another failure for this line. */ - ++failures; - failed_filename = filename; - failed_lines[line].count++; - - /* Determine whether to log header to console. */ - switch (verbosity) { - case VERBOSITY_LIGHT_REPORT: - log_console = (failed_lines[line].count < 2); - break; - default: - log_console = (verbosity >= VERBOSITY_FULL); - } - - /* Log file:line header for this failure */ - va_start(ap, fmt); -#if _MSC_VER - logprintf("%s(%d): ", filename, line); -#else - logprintf("%s:%d: ", filename, line); -#endif - vlogprintf(fmt, ap); - va_end(ap); - logprintf("\n"); - - if (msg != NULL && msg[0] != '\0') { - logprintf(" Description: %s\n", msg); - msg = NULL; - } - - /* Determine whether to log details to console. */ - if (verbosity == VERBOSITY_LIGHT_REPORT) - log_console = 0; -} - -/* Complete reporting of failed tests. */ -/* - * The 'extra' hook here is used by libarchive to include libarchive - * error messages with assertion failures. It could also be used - * to add strerror() output, for example. Just define the EXTRA_DUMP() - * macro appropriately. - */ -static void -failure_finish(void *extra) -{ - (void)extra; /* UNUSED (maybe) */ -#ifdef EXTRA_DUMP - if (extra != NULL) { - logprintf(" errno: %d\n", EXTRA_ERRNO(extra)); - logprintf(" detail: %s\n", EXTRA_DUMP(extra)); - } -#endif - - if (dump_on_failure) { - fprintf(stderr, - " *** forcing core dump so failure can be debugged ***\n"); - abort(); - } -} - -/* Inform user that we're skipping some checks. */ -void -test_skipping(const char *fmt, ...) -{ - char buff[1024]; - va_list ap; - - va_start(ap, fmt); - vsprintf(buff, fmt, ap); - va_end(ap); - /* Use failure() message if set. */ - msg = nextmsg; - nextmsg = NULL; - /* failure_start() isn't quite right, but is awfully convenient. */ - failure_start(skipping_filename, skipping_line, "SKIPPING: %s", buff); - --failures; /* Undo failures++ in failure_start() */ - /* Don't failure_finish() here. */ - /* Mark as skip, so doesn't count as failed test. */ - failed_lines[skipping_line].skip = 1; - ++skips; -} - -/* - * - * ASSERTIONS - * - */ - -/* Generic assert() just displays the failed condition. */ -int -assertion_assert(const char *file, int line, int value, - const char *condition, void *extra) -{ - assertion_count(file, line); - if (!value) { - failure_start(file, line, "Assertion failed: %s", condition); - failure_finish(extra); - } - return (value); -} - -/* chdir() and report any errors */ -int -assertion_chdir(const char *file, int line, const char *pathname) -{ - assertion_count(file, line); - if (chdir(pathname) == 0) - return (1); - failure_start(file, line, "chdir(\"%s\")", pathname); - failure_finish(NULL); - return (0); - -} - -/* Verify two integers are equal. */ -int -assertion_equal_int(const char *file, int line, - long long v1, const char *e1, long long v2, const char *e2, void *extra) -{ - assertion_count(file, line); - if (v1 == v2) - return (1); - failure_start(file, line, "%s != %s", e1, e2); - logprintf(" %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1); - logprintf(" %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2); - failure_finish(extra); - return (0); -} - -/* - * Utility to convert a single UTF-8 sequence. - */ -static int -_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) -{ - static const char utf8_count[256] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */ - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */ - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ - }; - int ch; - int cnt; - uint32_t wc; - - *pwc = 0; - - /* Sanity check. */ - if (n == 0) - return (0); - /* - * Decode 1-4 bytes depending on the value of the first byte. - */ - ch = (unsigned char)*s; - if (ch == 0) - return (0); /* Standard: return 0 for end-of-string. */ - cnt = utf8_count[ch]; - - /* Invalid sequence or there are not plenty bytes. */ - if (n < (size_t)cnt) - return (-1); - - /* Make a Unicode code point from a single UTF-8 sequence. */ - switch (cnt) { - case 1: /* 1 byte sequence. */ - *pwc = ch & 0x7f; - return (cnt); - case 2: /* 2 bytes sequence. */ - if ((s[1] & 0xc0) != 0x80) return (-1); - *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f); - return (cnt); - case 3: /* 3 bytes sequence. */ - if ((s[1] & 0xc0) != 0x80) return (-1); - if ((s[2] & 0xc0) != 0x80) return (-1); - wc = ((ch & 0x0f) << 12) - | ((s[1] & 0x3f) << 6) - | (s[2] & 0x3f); - if (wc < 0x800) - return (-1);/* Overlong sequence. */ - break; - case 4: /* 4 bytes sequence. */ - if (n < 4) - return (-1); - if ((s[1] & 0xc0) != 0x80) return (-1); - if ((s[2] & 0xc0) != 0x80) return (-1); - if ((s[3] & 0xc0) != 0x80) return (-1); - wc = ((ch & 0x07) << 18) - | ((s[1] & 0x3f) << 12) - | ((s[2] & 0x3f) << 6) - | (s[3] & 0x3f); - if (wc < 0x10000) - return (-1);/* Overlong sequence. */ - break; - default: - return (-1); - } - - /* The code point larger than 0x10FFFF is not legal - * Unicode values. */ - if (wc > 0x10FFFF) - return (-1); - /* Correctly gets a Unicode, returns used bytes. */ - *pwc = wc; - return (cnt); -} - -static void strdump(const char *e, const char *p, int ewidth, int utf8) -{ - const char *q = p; - - logprintf(" %*s = ", ewidth, e); - if (p == NULL) { - logprintf("NULL\n"); - return; - } - logprintf("\""); - while (*p != '\0') { - unsigned int c = 0xff & *p++; - switch (c) { - case '\a': logprintf("\\a"); break; - case '\b': logprintf("\\b"); break; - case '\n': logprintf("\\n"); break; - case '\r': logprintf("\\r"); break; - default: - if (c >= 32 && c < 127) - logprintf("%c", c); - else - logprintf("\\x%02X", c); - } - } - logprintf("\""); - logprintf(" (length %d)", q == NULL ? -1 : (int)strlen(q)); - - /* - * If the current string is UTF-8, dump its code points. - */ - if (utf8) { - size_t len; - uint32_t uc; - int n; - int cnt = 0; - - p = q; - len = strlen(p); - logprintf(" ["); - while ((n = _utf8_to_unicode(&uc, p, len)) > 0) { - if (p != q) - logprintf(" "); - logprintf("%04X", uc); - p += n; - len -= n; - cnt++; - } - logprintf("]"); - logprintf(" (count %d", cnt); - if (n < 0) { - logprintf(",unknown %d bytes", len); - } - logprintf(")"); - - } - logprintf("\n"); -} - -/* Verify two strings are equal, dump them if not. */ -int -assertion_equal_string(const char *file, int line, - const char *v1, const char *e1, - const char *v2, const char *e2, - void *extra, int utf8) -{ - int l1, l2; - - assertion_count(file, line); - if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0)) - return (1); - failure_start(file, line, "%s != %s", e1, e2); - l1 = (int)strlen(e1); - l2 = (int)strlen(e2); - if (l1 < l2) - l1 = l2; - strdump(e1, v1, l1, utf8); - strdump(e2, v2, l1, utf8); - failure_finish(extra); - return (0); -} - -static void -wcsdump(const char *e, const wchar_t *w) -{ - logprintf(" %s = ", e); - if (w == NULL) { - logprintf("(null)"); - return; - } - logprintf("\""); - while (*w != L'\0') { - unsigned int c = *w++; - if (c >= 32 && c < 127) - logprintf("%c", c); - else if (c < 256) - logprintf("\\x%02X", c); - else if (c < 0x10000) - logprintf("\\u%04X", c); - else - logprintf("\\U%08X", c); - } - logprintf("\"\n"); -} - -#ifndef HAVE_WCSCMP -static int -wcscmp(const wchar_t *s1, const wchar_t *s2) -{ - - while (*s1 == *s2++) { - if (*s1++ == L'\0') - return 0; - } - if (*s1 > *--s2) - return 1; - else - return -1; -} -#endif - -/* Verify that two wide strings are equal, dump them if not. */ -int -assertion_equal_wstring(const char *file, int line, - const wchar_t *v1, const char *e1, - const wchar_t *v2, const char *e2, - void *extra) -{ - assertion_count(file, line); - if (v1 == v2) - return (1); - if (v1 != NULL && v2 != NULL && wcscmp(v1, v2) == 0) - return (1); - failure_start(file, line, "%s != %s", e1, e2); - wcsdump(e1, v1); - wcsdump(e2, v2); - failure_finish(extra); - return (0); -} - -/* - * Pretty standard hexdump routine. As a bonus, if ref != NULL, then - * any bytes in p that differ from ref will be highlighted with '_' - * before and after the hex value. - */ -static void -hexdump(const char *p, const char *ref, size_t l, size_t offset) -{ - size_t i, j; - char sep; - - if (p == NULL) { - logprintf("(null)\n"); - return; - } - for(i=0; i < l; i+=16) { - logprintf("%04x", (unsigned)(i + offset)); - sep = ' '; - for (j = 0; j < 16 && i + j < l; j++) { - if (ref != NULL && p[i + j] != ref[i + j]) - sep = '_'; - logprintf("%c%02x", sep, 0xff & (int)p[i+j]); - if (ref != NULL && p[i + j] == ref[i + j]) - sep = ' '; - } - for (; j < 16; j++) { - logprintf("%c ", sep); - sep = ' '; - } - logprintf("%c", sep); - for (j=0; j < 16 && i + j < l; j++) { - int c = p[i + j]; - if (c >= ' ' && c <= 126) - logprintf("%c", c); - else - logprintf("."); - } - logprintf("\n"); - } -} - -/* Verify that two blocks of memory are the same, display the first - * block of differences if they're not. */ -int -assertion_equal_mem(const char *file, int line, - const void *_v1, const char *e1, - const void *_v2, const char *e2, - size_t l, const char *ld, void *extra) -{ - const char *v1 = (const char *)_v1; - const char *v2 = (const char *)_v2; - size_t offset; - - assertion_count(file, line); - if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0)) - return (1); - if (v1 == NULL || v2 == NULL) - return (0); - - failure_start(file, line, "%s != %s", e1, e2); - logprintf(" size %s = %d\n", ld, (int)l); - /* Dump 48 bytes (3 lines) so that the first difference is - * in the second line. */ - offset = 0; - while (l > 64 && memcmp(v1, v2, 32) == 0) { - /* Two lines agree, so step forward one line. */ - v1 += 16; - v2 += 16; - l -= 16; - offset += 16; - } - logprintf(" Dump of %s\n", e1); - hexdump(v1, v2, l < 128 ? l : 128, offset); - logprintf(" Dump of %s\n", e2); - hexdump(v2, v1, l < 128 ? l : 128, offset); - logprintf("\n"); - failure_finish(extra); - return (0); -} - -/* Verify that a block of memory is filled with the specified byte. */ -int -assertion_memory_filled_with(const char *file, int line, - const void *_v1, const char *vd, - size_t l, const char *ld, - char b, const char *bd, void *extra) -{ - const char *v1 = (const char *)_v1; - size_t c = 0; - size_t i; - (void)ld; /* UNUSED */ - - assertion_count(file, line); - - for (i = 0; i < l; ++i) { - if (v1[i] == b) { - ++c; - } - } - if (c == l) - return (1); - - failure_start(file, line, "%s (size %d) not filled with %s", vd, (int)l, bd); - logprintf(" Only %d bytes were correct\n", (int)c); - failure_finish(extra); - return (0); -} - -/* Verify that the named file exists and is empty. */ -int -assertion_empty_file(const char *filename, int line, const char *f1) -{ - char buff[1024]; - struct stat st; - ssize_t s; - FILE *f; - - assertion_count(filename, line); - - if (stat(f1, &st) != 0) { - failure_start(filename, line, "Stat failed: %s", f1); - failure_finish(NULL); - return (0); - } - if (st.st_size == 0) - return (1); - - failure_start(filename, line, "File should be empty: %s", f1); - logprintf(" File size: %d\n", (int)st.st_size); - logprintf(" Contents:\n"); - f = fopen(f1, "rb"); - if (f == NULL) { - logprintf(" Unable to open %s\n", f1); - } else { - s = ((off_t)sizeof(buff) < st.st_size) ? - (ssize_t)sizeof(buff) : (ssize_t)st.st_size; - s = fread(buff, 1, s, f); - hexdump(buff, NULL, s, 0); - fclose(f); - } - failure_finish(NULL); - return (0); -} - -/* Verify that the named file exists and is not empty. */ -int -assertion_non_empty_file(const char *filename, int line, const char *f1) -{ - struct stat st; - - assertion_count(filename, line); - - if (stat(f1, &st) != 0) { - failure_start(filename, line, "Stat failed: %s", f1); - failure_finish(NULL); - return (0); - } - if (st.st_size == 0) { - failure_start(filename, line, "File empty: %s", f1); - failure_finish(NULL); - return (0); - } - return (1); -} - -/* Verify that two files have the same contents. */ -/* TODO: hexdump the first bytes that actually differ. */ -int -assertion_equal_file(const char *filename, int line, const char *fn1, const char *fn2) -{ - char buff1[1024]; - char buff2[1024]; - FILE *f1, *f2; - int n1, n2; - - assertion_count(filename, line); - - f1 = fopen(fn1, "rb"); - f2 = fopen(fn2, "rb"); - if (f1 == NULL || f2 == NULL) { - if (f1) fclose(f1); - if (f2) fclose(f2); - return (0); - } - for (;;) { - n1 = (int)fread(buff1, 1, sizeof(buff1), f1); - n2 = (int)fread(buff2, 1, sizeof(buff2), f2); - if (n1 != n2) - break; - if (n1 == 0 && n2 == 0) { - fclose(f1); - fclose(f2); - return (1); - } - if (memcmp(buff1, buff2, n1) != 0) - break; - } - fclose(f1); - fclose(f2); - failure_start(filename, line, "Files not identical"); - logprintf(" file1=\"%s\"\n", fn1); - logprintf(" file2=\"%s\"\n", fn2); - failure_finish(NULL); - return (0); -} - -/* Verify that the named file does exist. */ -int -assertion_file_exists(const char *filename, int line, const char *f) -{ - assertion_count(filename, line); - -#if defined(_WIN32) && !defined(__CYGWIN__) - if (!_access(f, 0)) - return (1); -#else - if (!access(f, F_OK)) - return (1); -#endif - failure_start(filename, line, "File should exist: %s", f); - failure_finish(NULL); - return (0); -} - -/* Verify that the named file doesn't exist. */ -int -assertion_file_not_exists(const char *filename, int line, const char *f) -{ - assertion_count(filename, line); - -#if defined(_WIN32) && !defined(__CYGWIN__) - if (_access(f, 0)) - return (1); -#else - if (access(f, F_OK)) - return (1); -#endif - failure_start(filename, line, "File should not exist: %s", f); - failure_finish(NULL); - return (0); -} - -/* Compare the contents of a file to a block of memory. */ -int -assertion_file_contents(const char *filename, int line, const void *buff, int s, const char *fn) -{ - char *contents; - FILE *f; - int n; - - assertion_count(filename, line); - - f = fopen(fn, "rb"); - if (f == NULL) { - failure_start(filename, line, - "File should exist: %s", fn); - failure_finish(NULL); - return (0); - } - contents = malloc(s * 2); - n = (int)fread(contents, 1, s * 2, f); - fclose(f); - if (n == s && memcmp(buff, contents, s) == 0) { - free(contents); - return (1); - } - failure_start(filename, line, "File contents don't match"); - logprintf(" file=\"%s\"\n", fn); - if (n > 0) - hexdump(contents, buff, n > 512 ? 512 : n, 0); - else { - logprintf(" File empty, contents should be:\n"); - hexdump(buff, NULL, s > 512 ? 512 : s, 0); - } - failure_finish(NULL); - free(contents); - return (0); -} - -/* Check the contents of a text file, being tolerant of line endings. */ -int -assertion_text_file_contents(const char *filename, int line, const char *buff, const char *fn) -{ - char *contents; - const char *btxt, *ftxt; - FILE *f; - int n, s; - - assertion_count(filename, line); - f = fopen(fn, "r"); - if (f == NULL) { - failure_start(filename, line, - "File doesn't exist: %s", fn); - failure_finish(NULL); - return (0); - } - s = (int)strlen(buff); - contents = malloc(s * 2 + 128); - n = (int)fread(contents, 1, s * 2 + 128 - 1, f); - if (n >= 0) - contents[n] = '\0'; - fclose(f); - /* Compare texts. */ - btxt = buff; - ftxt = (const char *)contents; - while (*btxt != '\0' && *ftxt != '\0') { - if (*btxt == *ftxt) { - ++btxt; - ++ftxt; - continue; - } - if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') { - /* Pass over different new line characters. */ - ++btxt; - ftxt += 2; - continue; - } - break; - } - if (*btxt == '\0' && *ftxt == '\0') { - free(contents); - return (1); - } - failure_start(filename, line, "Contents don't match"); - logprintf(" file=\"%s\"\n", fn); - if (n > 0) { - hexdump(contents, buff, n, 0); - logprintf(" expected\n", fn); - hexdump(buff, contents, s, 0); - } else { - logprintf(" File empty, contents should be:\n"); - hexdump(buff, NULL, s, 0); - } - failure_finish(NULL); - free(contents); - return (0); -} - -/* Verify that a text file contains the specified lines, regardless of order */ -/* This could be more efficient if we sorted both sets of lines, etc, but - * since this is used only for testing and only ever deals with a dozen or so - * lines at a time, this relatively crude approach is just fine. */ -int -assertion_file_contains_lines_any_order(const char *file, int line, - const char *pathname, const char *lines[]) -{ - char *buff; - size_t buff_size; - size_t expected_count, actual_count, i, j; - char **expected = NULL; - char *p, **actual = NULL; - char c; - int expected_failure = 0, actual_failure = 0, retval = 0; - - assertion_count(file, line); - - buff = slurpfile(&buff_size, "%s", pathname); - if (buff == NULL) { - failure_start(pathname, line, "Can't read file: %s", pathname); - failure_finish(NULL); - return (0); - } - - /* Make a copy of the provided lines and count up the expected - * file size. */ - for (i = 0; lines[i] != NULL; ++i) { - } - expected_count = i; - if (expected_count) { - expected = malloc(sizeof(char *) * expected_count); - if (expected == NULL) { - failure_start(pathname, line, "Can't allocate memory"); - failure_finish(NULL); - goto done; - } - for (i = 0; lines[i] != NULL; ++i) { - expected[i] = strdup(lines[i]); - } - } - - /* Break the file into lines */ - actual_count = 0; - for (c = '\0', p = buff; p < buff + buff_size; ++p) { - if (*p == '\x0d' || *p == '\x0a') - *p = '\0'; - if (c == '\0' && *p != '\0') - ++actual_count; - c = *p; - } - if (actual_count) { - actual = calloc(sizeof(char *), actual_count); - if (actual == NULL) { - failure_start(pathname, line, "Can't allocate memory"); - failure_finish(NULL); - goto done; - } - for (j = 0, p = buff; p < buff + buff_size; - p += 1 + strlen(p)) { - if (*p != '\0') { - actual[j] = p; - ++j; - } - } - } - - /* Erase matching lines from both lists */ - for (i = 0; i < expected_count; ++i) { - if (expected[i] == NULL) - continue; - for (j = 0; j < actual_count; ++j) { - if (actual[j] == NULL) - continue; - if (strcmp(expected[i], actual[j]) == 0) { - free(expected[i]); - expected[i] = NULL; - actual[j] = NULL; - break; - } - } - } - - /* If there's anything left, it's a failure */ - for (i = 0; i < expected_count; ++i) { - if (expected[i] != NULL) - ++expected_failure; - } - for (j = 0; j < actual_count; ++j) { - if (actual[j] != NULL) - ++actual_failure; - } - if (expected_failure == 0 && actual_failure == 0) { - retval = 1; - goto done; - } - failure_start(file, line, "File doesn't match: %s", pathname); - for (i = 0; i < expected_count; ++i) { - if (expected[i] != NULL) - logprintf(" Expected but not present: %s\n", expected[i]); - } - for (j = 0; j < actual_count; ++j) { - if (actual[j] != NULL) - logprintf(" Present but not expected: %s\n", actual[j]); - } - failure_finish(NULL); -done: - free(actual); - free(buff); - for (i = 0; i < expected_count; ++i) - free(expected[i]); - free(expected); - - return (retval); -} - -/* Verify that a text file does not contains the specified strings */ -int -assertion_file_contains_no_invalid_strings(const char *file, int line, - const char *pathname, const char *strings[]) -{ - char *buff; - int i; - - buff = slurpfile(NULL, "%s", pathname); - if (buff == NULL) { - failure_start(file, line, "Can't read file: %s", pathname); - failure_finish(NULL); - return (0); - } - - for (i = 0; strings[i] != NULL; ++i) { - if (strstr(buff, strings[i]) != NULL) { - failure_start(file, line, "Invalid string in %s: %s", pathname, - strings[i]); - failure_finish(NULL); - free(buff); - return(0); - } - } - - free(buff); - return (0); -} - -/* Test that two paths point to the same file. */ -/* As a side-effect, asserts that both files exist. */ -static int -is_hardlink(const char *file, int line, - const char *path1, const char *path2) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2; - int r; - - assertion_count(file, line); - r = my_GetFileInformationByName(path1, &bhfi1); - if (r == 0) { - failure_start(file, line, "File %s can't be inspected?", path1); - failure_finish(NULL); - return (0); - } - r = my_GetFileInformationByName(path2, &bhfi2); - if (r == 0) { - failure_start(file, line, "File %s can't be inspected?", path2); - failure_finish(NULL); - return (0); - } - return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber - && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh - && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow); -#else - struct stat st1, st2; - int r; - - assertion_count(file, line); - r = lstat(path1, &st1); - if (r != 0) { - failure_start(file, line, "File should exist: %s", path1); - failure_finish(NULL); - return (0); - } - r = lstat(path2, &st2); - if (r != 0) { - failure_start(file, line, "File should exist: %s", path2); - failure_finish(NULL); - return (0); - } - return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev); -#endif -} - -int -assertion_is_hardlink(const char *file, int line, - const char *path1, const char *path2) -{ - if (is_hardlink(file, line, path1, path2)) - return (1); - failure_start(file, line, - "Files %s and %s are not hardlinked", path1, path2); - failure_finish(NULL); - return (0); -} - -int -assertion_is_not_hardlink(const char *file, int line, - const char *path1, const char *path2) -{ - if (!is_hardlink(file, line, path1, path2)) - return (1); - failure_start(file, line, - "Files %s and %s should not be hardlinked", path1, path2); - failure_finish(NULL); - return (0); -} - -/* Verify a/b/mtime of 'pathname'. */ -/* If 'recent', verify that it's within last 10 seconds. */ -static int -assertion_file_time(const char *file, int line, - const char *pathname, long t, long nsec, char type, int recent) -{ - long long filet, filet_nsec; - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) -#define EPOC_TIME (116444736000000000ULL) - FILETIME fxtime, fbirthtime, fatime, fmtime; - ULARGE_INTEGER wintm; - HANDLE h; - fxtime.dwLowDateTime = 0; - fxtime.dwHighDateTime = 0; - - assertion_count(file, line); - /* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open - * a directory file. If not, CreateFile() will fail when - * the pathname is a directory. */ - h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) { - failure_start(file, line, "Can't access %s\n", pathname); - failure_finish(NULL); - return (0); - } - r = GetFileTime(h, &fbirthtime, &fatime, &fmtime); - switch (type) { - case 'a': fxtime = fatime; break; - case 'b': fxtime = fbirthtime; break; - case 'm': fxtime = fmtime; break; - } - CloseHandle(h); - if (r == 0) { - failure_start(file, line, "Can't GetFileTime %s\n", pathname); - failure_finish(NULL); - return (0); - } - wintm.LowPart = fxtime.dwLowDateTime; - wintm.HighPart = fxtime.dwHighDateTime; - filet = (wintm.QuadPart - EPOC_TIME) / 10000000; - filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100; - nsec = (nsec / 100) * 100; /* Round the request */ -#else - struct stat st; - - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0) { - failure_start(file, line, "Can't stat %s\n", pathname); - failure_finish(NULL); - return (0); - } - switch (type) { - case 'a': filet = st.st_atime; break; - case 'm': filet = st.st_mtime; break; - case 'b': filet = 0; break; - default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); - exit(1); - } -#if defined(__FreeBSD__) - switch (type) { - case 'a': filet_nsec = st.st_atimespec.tv_nsec; break; - case 'b': filet = st.st_birthtime; - /* FreeBSD filesystems that don't support birthtime - * (e.g., UFS1) always return -1 here. */ - if (filet == -1) { - return (1); - } - filet_nsec = st.st_birthtimespec.tv_nsec; break; - case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break; - default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type); - exit(1); - } - /* FreeBSD generally only stores to microsecond res, so round. */ - filet_nsec = (filet_nsec / 1000) * 1000; - nsec = (nsec / 1000) * 1000; -#else - filet_nsec = nsec = 0; /* Generic POSIX only has whole seconds. */ - if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */ -#if defined(__HAIKU__) - if (type == 'a') return (1); /* Haiku doesn't have atime. */ -#endif -#endif -#endif - if (recent) { - /* Check that requested time is up-to-date. */ - time_t now = time(NULL); - if (filet < now - 10 || filet > now + 1) { - failure_start(file, line, - "File %s has %ctime %lld, %lld seconds ago\n", - pathname, type, filet, now - filet); - failure_finish(NULL); - return (0); - } - } else if (filet != t || filet_nsec != nsec) { - failure_start(file, line, - "File %s has %ctime %lld.%09lld, expected %lld.%09lld", - pathname, type, filet, filet_nsec, t, nsec); - failure_finish(NULL); - return (0); - } - return (1); -} - -/* Verify atime of 'pathname'. */ -int -assertion_file_atime(const char *file, int line, - const char *pathname, long t, long nsec) -{ - return assertion_file_time(file, line, pathname, t, nsec, 'a', 0); -} - -/* Verify atime of 'pathname' is up-to-date. */ -int -assertion_file_atime_recent(const char *file, int line, const char *pathname) -{ - return assertion_file_time(file, line, pathname, 0, 0, 'a', 1); -} - -/* Verify birthtime of 'pathname'. */ -int -assertion_file_birthtime(const char *file, int line, - const char *pathname, long t, long nsec) -{ - return assertion_file_time(file, line, pathname, t, nsec, 'b', 0); -} - -/* Verify birthtime of 'pathname' is up-to-date. */ -int -assertion_file_birthtime_recent(const char *file, int line, - const char *pathname) -{ - return assertion_file_time(file, line, pathname, 0, 0, 'b', 1); -} - -/* Verify mode of 'pathname'. */ -int -assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode) -{ - int mode; - int r; - - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - failure_start(file, line, "assertFileMode not yet implemented for Windows"); - (void)mode; /* UNUSED */ - (void)r; /* UNUSED */ -#else - { - struct stat st; - r = lstat(pathname, &st); - mode = (int)(st.st_mode & 0777); - } - if (r == 0 && mode == expected_mode) - return (1); - failure_start(file, line, "File %s has mode %o, expected %o", - pathname, mode, expected_mode); -#endif - failure_finish(NULL); - return (0); -} - -/* Verify mtime of 'pathname'. */ -int -assertion_file_mtime(const char *file, int line, - const char *pathname, long t, long nsec) -{ - return assertion_file_time(file, line, pathname, t, nsec, 'm', 0); -} - -/* Verify mtime of 'pathname' is up-to-date. */ -int -assertion_file_mtime_recent(const char *file, int line, const char *pathname) -{ - return assertion_file_time(file, line, pathname, 0, 0, 'm', 1); -} - -/* Verify number of links to 'pathname'. */ -int -assertion_file_nlinks(const char *file, int line, - const char *pathname, int nlinks) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - BY_HANDLE_FILE_INFORMATION bhfi; - int r; - - assertion_count(file, line); - r = my_GetFileInformationByName(pathname, &bhfi); - if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks) - return (1); - failure_start(file, line, "File %s has %d links, expected %d", - pathname, bhfi.nNumberOfLinks, nlinks); - failure_finish(NULL); - return (0); -#else - struct stat st; - int r; - - assertion_count(file, line); - r = lstat(pathname, &st); - if (r == 0 && (int)st.st_nlink == nlinks) - return (1); - failure_start(file, line, "File %s has %d links, expected %d", - pathname, st.st_nlink, nlinks); - failure_finish(NULL); - return (0); -#endif -} - -/* Verify size of 'pathname'. */ -int -assertion_file_size(const char *file, int line, const char *pathname, long size) -{ - int64_t filesize; - int r; - - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - { - BY_HANDLE_FILE_INFORMATION bhfi; - r = !my_GetFileInformationByName(pathname, &bhfi); - filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow; - } -#else - { - struct stat st; - r = lstat(pathname, &st); - filesize = st.st_size; - } -#endif - if (r == 0 && filesize == size) - return (1); - failure_start(file, line, "File %s has size %ld, expected %ld", - pathname, (long)filesize, (long)size); - failure_finish(NULL); - return (0); -} - -/* Assert that 'pathname' is a dir. If mode >= 0, verify that too. */ -int -assertion_is_dir(const char *file, int line, const char *pathname, int mode) -{ - struct stat st; - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)mode; /* UNUSED */ -#endif - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0) { - failure_start(file, line, "Dir should exist: %s", pathname); - failure_finish(NULL); - return (0); - } - if (!S_ISDIR(st.st_mode)) { - failure_start(file, line, "%s is not a dir", pathname); - failure_finish(NULL); - return (0); - } -#if !defined(_WIN32) || defined(__CYGWIN__) - /* Windows doesn't handle permissions the same way as POSIX, - * so just ignore the mode tests. */ - /* TODO: Can we do better here? */ - if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { - failure_start(file, line, "Dir %s has wrong mode", pathname); - logprintf(" Expected: 0%3o\n", mode); - logprintf(" Found: 0%3o\n", st.st_mode & 07777); - failure_finish(NULL); - return (0); - } -#endif - return (1); -} - -/* Verify that 'pathname' is a regular file. If 'mode' is >= 0, - * verify that too. */ -int -assertion_is_reg(const char *file, int line, const char *pathname, int mode) -{ - struct stat st; - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)mode; /* UNUSED */ -#endif - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0 || !S_ISREG(st.st_mode)) { - failure_start(file, line, "File should exist: %s", pathname); - failure_finish(NULL); - return (0); - } -#if !defined(_WIN32) || defined(__CYGWIN__) - /* Windows doesn't handle permissions the same way as POSIX, - * so just ignore the mode tests. */ - /* TODO: Can we do better here? */ - if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) { - failure_start(file, line, "File %s has wrong mode", pathname); - logprintf(" Expected: 0%3o\n", mode); - logprintf(" Found: 0%3o\n", st.st_mode & 07777); - failure_finish(NULL); - return (0); - } -#endif - return (1); -} - -/* Check whether 'pathname' is a symbolic link. If 'contents' is - * non-NULL, verify that the symlink has those contents. */ -static int -is_symlink(const char *file, int line, - const char *pathname, const char *contents) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)pathname; /* UNUSED */ - (void)contents; /* UNUSED */ - assertion_count(file, line); - /* Windows sort-of has real symlinks, but they're only usable - * by privileged users and are crippled even then, so there's - * really not much point in bothering with this. */ - return (0); -#else - char buff[301]; - struct stat st; - ssize_t linklen; - int r; - - assertion_count(file, line); - r = lstat(pathname, &st); - if (r != 0) { - failure_start(file, line, - "Symlink should exist: %s", pathname); - failure_finish(NULL); - return (0); - } - if (!S_ISLNK(st.st_mode)) - return (0); - if (contents == NULL) - return (1); - linklen = readlink(pathname, buff, sizeof(buff) - 1); - if (linklen < 0) { - failure_start(file, line, "Can't read symlink %s", pathname); - failure_finish(NULL); - return (0); - } - buff[linklen] = '\0'; - if (strcmp(buff, contents) != 0) - return (0); - return (1); -#endif -} - -/* Assert that path is a symlink that (optionally) contains contents. */ -int -assertion_is_symlink(const char *file, int line, - const char *path, const char *contents) -{ - if (is_symlink(file, line, path, contents)) - return (1); - if (contents) - failure_start(file, line, "File %s is not a symlink to %s", - path, contents); - else - failure_start(file, line, "File %s is not a symlink", path); - failure_finish(NULL); - return (0); -} - - -/* Create a directory and report any errors. */ -int -assertion_make_dir(const char *file, int line, const char *dirname, int mode) -{ - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - (void)mode; /* UNUSED */ - if (0 == _mkdir(dirname)) - return (1); -#else - if (0 == mkdir(dirname, mode)) { - if (0 == chmod(dirname, mode)) { - assertion_file_mode(file, line, dirname, mode); - return (1); - } - } -#endif - failure_start(file, line, "Could not create directory %s", dirname); - failure_finish(NULL); - return(0); -} - -/* Create a file with the specified contents and report any failures. */ -int -assertion_make_file(const char *file, int line, - const char *path, int mode, int csize, const void *contents) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - /* TODO: Rework this to set file mode as well. */ - FILE *f; - (void)mode; /* UNUSED */ - assertion_count(file, line); - f = fopen(path, "wb"); - if (f == NULL) { - failure_start(file, line, "Could not create file %s", path); - failure_finish(NULL); - return (0); - } - if (contents != NULL) { - size_t wsize; - - if (csize < 0) - wsize = strlen(contents); - else - wsize = (size_t)csize; - if (wsize != fwrite(contents, 1, wsize, f)) { - fclose(f); - failure_start(file, line, - "Could not write file %s", path); - failure_finish(NULL); - return (0); - } - } - fclose(f); - return (1); -#else - int fd; - assertion_count(file, line); - fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644); - if (fd < 0) { - failure_start(file, line, "Could not create %s", path); - failure_finish(NULL); - return (0); - } - if (0 != chmod(path, mode)) { - failure_start(file, line, "Could not chmod %s", path); - failure_finish(NULL); - close(fd); - return (0); - } - if (contents != NULL) { - ssize_t wsize; - - if (csize < 0) - wsize = (ssize_t)strlen(contents); - else - wsize = (ssize_t)csize; - if (wsize != write(fd, contents, wsize)) { - close(fd); - failure_start(file, line, - "Could not write to %s", path); - failure_finish(NULL); - close(fd); - return (0); - } - } - close(fd); - assertion_file_mode(file, line, path, mode); - return (1); -#endif -} - -/* Create a hardlink and report any failures. */ -int -assertion_make_hardlink(const char *file, int line, - const char *newpath, const char *linkto) -{ - int succeeded; - - assertion_count(file, line); -#if defined(_WIN32) && !defined(__CYGWIN__) - succeeded = my_CreateHardLinkA(newpath, linkto); -#elif HAVE_LINK - succeeded = !link(linkto, newpath); -#else - succeeded = 0; -#endif - if (succeeded) - return (1); - failure_start(file, line, "Could not create hardlink"); - logprintf(" New link: %s\n", newpath); - logprintf(" Old name: %s\n", linkto); - failure_finish(NULL); - return(0); -} - -/* Create a symlink and report any failures. */ -int -assertion_make_symlink(const char *file, int line, - const char *newpath, const char *linkto) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - int targetIsDir = 0; /* TODO: Fix this */ - assertion_count(file, line); - if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir)) - return (1); -#elif HAVE_SYMLINK - assertion_count(file, line); - if (0 == symlink(linkto, newpath)) - return (1); -#endif - failure_start(file, line, "Could not create symlink"); - logprintf(" New link: %s\n", newpath); - logprintf(" Old name: %s\n", linkto); - failure_finish(NULL); - return(0); -} - -/* Set umask, report failures. */ -int -assertion_umask(const char *file, int line, int mask) -{ - assertion_count(file, line); - (void)file; /* UNUSED */ - (void)line; /* UNUSED */ - umask(mask); - return (1); -} - -/* Set times, report failures. */ -int -assertion_utimes(const char *file, int line, - const char *pathname, long at, long at_nsec, long mt, long mt_nsec) -{ - int r; - -#if defined(_WIN32) && !defined(__CYGWIN__) -#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\ - + (((nsec)/1000)*10)) - HANDLE h; - ULARGE_INTEGER wintm; - FILETIME fatime, fmtime; - FILETIME *pat, *pmt; - - assertion_count(file, line); - h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h == INVALID_HANDLE_VALUE) { - failure_start(file, line, "Can't access %s\n", pathname); - failure_finish(NULL); - return (0); - } - - if (at > 0 || at_nsec > 0) { - wintm.QuadPart = WINTIME(at, at_nsec); - fatime.dwLowDateTime = wintm.LowPart; - fatime.dwHighDateTime = wintm.HighPart; - pat = &fatime; - } else - pat = NULL; - if (mt > 0 || mt_nsec > 0) { - wintm.QuadPart = WINTIME(mt, mt_nsec); - fmtime.dwLowDateTime = wintm.LowPart; - fmtime.dwHighDateTime = wintm.HighPart; - pmt = &fmtime; - } else - pmt = NULL; - if (pat != NULL || pmt != NULL) - r = SetFileTime(h, NULL, pat, pmt); - else - r = 1; - CloseHandle(h); - if (r == 0) { - failure_start(file, line, "Can't SetFileTime %s\n", pathname); - failure_finish(NULL); - return (0); - } - return (1); -#else /* defined(_WIN32) && !defined(__CYGWIN__) */ - struct stat st; - struct timeval times[2]; - -#if !defined(__FreeBSD__) - mt_nsec = at_nsec = 0; /* Generic POSIX only has whole seconds. */ -#endif - if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0) - return (1); - - r = lstat(pathname, &st); - if (r < 0) { - failure_start(file, line, "Can't stat %s\n", pathname); - failure_finish(NULL); - return (0); - } - - if (mt == 0 && mt_nsec == 0) { - mt = st.st_mtime; -#if defined(__FreeBSD__) - mt_nsec = st.st_mtimespec.tv_nsec; - /* FreeBSD generally only stores to microsecond res, so round. */ - mt_nsec = (mt_nsec / 1000) * 1000; -#endif - } - if (at == 0 && at_nsec == 0) { - at = st.st_atime; -#if defined(__FreeBSD__) - at_nsec = st.st_atimespec.tv_nsec; - /* FreeBSD generally only stores to microsecond res, so round. */ - at_nsec = (at_nsec / 1000) * 1000; -#endif - } - - times[1].tv_sec = mt; - times[1].tv_usec = mt_nsec / 1000; - - times[0].tv_sec = at; - times[0].tv_usec = at_nsec / 1000; - -#ifdef HAVE_LUTIMES - r = lutimes(pathname, times); -#else - r = utimes(pathname, times); -#endif - if (r < 0) { - failure_start(file, line, "Can't utimes %s\n", pathname); - failure_finish(NULL); - return (0); - } - return (1); -#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ -} - -/* Set nodump, report failures. */ -int -assertion_nodump(const char *file, int line, const char *pathname) -{ -#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) - int r; - - assertion_count(file, line); - r = chflags(pathname, UF_NODUMP); - if (r < 0) { - failure_start(file, line, "Can't set nodump %s\n", pathname); - failure_finish(NULL); - return (0); - } -#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ - && defined(EXT2_NODUMP_FL) - int fd, r, flags; - - assertion_count(file, line); - fd = open(pathname, O_RDONLY | O_NONBLOCK); - if (fd < 0) { - failure_start(file, line, "Can't open %s\n", pathname); - failure_finish(NULL); - return (0); - } - r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); - if (r < 0) { - failure_start(file, line, "Can't get flags %s\n", pathname); - failure_finish(NULL); - return (0); - } - flags |= EXT2_NODUMP_FL; - r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); - if (r < 0) { - failure_start(file, line, "Can't set nodump %s\n", pathname); - failure_finish(NULL); - return (0); - } - close(fd); -#else - (void)pathname; /* UNUSED */ - assertion_count(file, line); -#endif - return (1); -} - -/* - * - * UTILITIES for use by tests. - * - */ - -/* - * Check whether platform supports symlinks. This is intended - * for tests to use in deciding whether to bother testing symlink - * support; if the platform doesn't support symlinks, there's no point - * in checking whether the program being tested can create them. - * - * Note that the first time this test is called, we actually go out to - * disk to create and verify a symlink. This is necessary because - * symlink support is actually a property of a particular filesystem - * and can thus vary between directories on a single system. After - * the first call, this returns the cached result from memory, so it's - * safe to call it as often as you wish. - */ -int -canSymlink(void) -{ - /* Remember the test result */ - static int value = 0, tested = 0; - if (tested) - return (value); - - ++tested; - assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a"); - /* Note: Cygwin has its own symlink() emulation that does not - * use the Win32 CreateSymbolicLink() function. */ -#if defined(_WIN32) && !defined(__CYGWIN__) - value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0) - && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0"); -#elif HAVE_SYMLINK - value = (0 == symlink("canSymlink.0", "canSymlink.1")) - && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0"); -#endif - return (value); -} - -/* Platform-dependent options for hiding the output of a subcommand. */ -#if defined(_WIN32) && !defined(__CYGWIN__) -static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */ -#else -static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */ -#endif -/* - * Can this platform run the bzip2 program? - */ -int -canBzip2(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("bzip2 -d -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the grzip program? - */ -int -canGrzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("grzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the gzip program? - */ -int -canGzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("gzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lrzip program? - */ -int -canRunCommand(const char *cmd) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("%s %s", cmd, redirectArgs) == 0) - value = 1; - } - return (value); -} - -int -canLrzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lrzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lz4 program? - */ -int -canLz4(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lz4 -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lzip program? - */ -int -canLzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lzma program? - */ -int -canLzma(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzma -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the lzop program? - */ -int -canLzop(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzop -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this platform run the xz program? - */ -int -canXz(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("xz -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} - -/* - * Can this filesystem handle nodump flags. - */ -#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) - -int -canNodump(void) -{ - const char *path = "cannodumptest"; - struct stat sb; - - assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); - if (chflags(path, UF_NODUMP) < 0) - return (0); - if (stat(path, &sb) < 0) - return (0); - if (sb.st_flags & UF_NODUMP) - return (1); - return (0); -} - -#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\ - && defined(EXT2_NODUMP_FL) - -int -canNodump(void) -{ - const char *path = "cannodumptest"; - int fd, r, flags; - - assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL); - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) - return (0); - r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); - if (r < 0) - return (0); - flags |= EXT2_NODUMP_FL; - r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags); - if (r < 0) - return (0); - close(fd); - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) - return (0); - r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags); - if (r < 0) - return (0); - close(fd); - if (flags & EXT2_NODUMP_FL) - return (1); - return (0); -} - -#else - -int -canNodump() -{ - return (0); -} - -#endif - -/* - * Sleep as needed; useful for verifying disk timestamp changes by - * ensuring that the wall-clock time has actually changed before we - * go back to re-read something from disk. - */ -void -sleepUntilAfter(time_t t) -{ - while (t >= time(NULL)) -#if defined(_WIN32) && !defined(__CYGWIN__) - Sleep(500); -#else - sleep(1); -#endif -} - -/* - * Call standard system() call, but build up the command line using - * sprintf() conventions. - */ -int -systemf(const char *fmt, ...) -{ - char buff[8192]; - va_list ap; - int r; - - va_start(ap, fmt); - vsprintf(buff, fmt, ap); - if (verbosity > VERBOSITY_FULL) - logprintf("Cmd: %s\n", buff); - r = system(buff); - va_end(ap); - return (r); -} - -/* - * Slurp a file into memory for ease of comparison and testing. - * Returns size of file in 'sizep' if non-NULL, null-terminates - * data in memory for ease of use. - */ -char * -slurpfile(size_t * sizep, const char *fmt, ...) -{ - char filename[8192]; - struct stat st; - va_list ap; - char *p; - ssize_t bytes_read; - FILE *f; - int r; - - va_start(ap, fmt); - vsprintf(filename, fmt, ap); - va_end(ap); - - f = fopen(filename, "rb"); - if (f == NULL) { - /* Note: No error; non-existent file is okay here. */ - return (NULL); - } - r = fstat(fileno(f), &st); - if (r != 0) { - logprintf("Can't stat file %s\n", filename); - fclose(f); - return (NULL); - } - p = malloc((size_t)st.st_size + 1); - if (p == NULL) { - logprintf("Can't allocate %ld bytes of memory to read file %s\n", - (long int)st.st_size, filename); - fclose(f); - return (NULL); - } - bytes_read = fread(p, 1, (size_t)st.st_size, f); - if (bytes_read < st.st_size) { - logprintf("Can't read file %s\n", filename); - fclose(f); - free(p); - return (NULL); - } - p[st.st_size] = '\0'; - if (sizep != NULL) - *sizep = (size_t)st.st_size; - fclose(f); - return (p); -} - -/* - * Slurp a file into memory for ease of comparison and testing. - * Returns size of file in 'sizep' if non-NULL, null-terminates - * data in memory for ease of use. - */ -void -dumpfile(const char *filename, void *data, size_t len) -{ - ssize_t bytes_written; - FILE *f; - - f = fopen(filename, "wb"); - if (f == NULL) { - logprintf("Can't open file %s for writing\n", filename); - return; - } - bytes_written = fwrite(data, 1, len, f); - if (bytes_written < (ssize_t)len) - logprintf("Can't write file %s\n", filename); - fclose(f); -} - -/* Read a uuencoded file from the reference directory, decode, and - * write the result into the current directory. */ -#define VALID_UUDECODE(c) (c >= 32 && c <= 96) -#define UUDECODE(c) (((c) - 0x20) & 0x3f) -void -extract_reference_file(const char *name) -{ - char buff[1024]; - FILE *in, *out; - - sprintf(buff, "%s/%s.uu", refdir, name); - in = fopen(buff, "r"); - failure("Couldn't open reference file %s", buff); - assert(in != NULL); - if (in == NULL) - return; - /* Read up to and including the 'begin' line. */ - for (;;) { - if (fgets(buff, sizeof(buff), in) == NULL) { - /* TODO: This is a failure. */ - goto done; - } - if (memcmp(buff, "begin ", 6) == 0) - break; - } - /* Now, decode the rest and write it. */ - out = fopen(name, "wb"); - while (fgets(buff, sizeof(buff), in) != NULL) { - char *p = buff; - int bytes; - - if (memcmp(buff, "end", 3) == 0) - break; - - bytes = UUDECODE(*p++); - while (bytes > 0) { - int n = 0; - /* Write out 1-3 bytes from that. */ - if (bytes > 0) { - assert(VALID_UUDECODE(p[0])); - assert(VALID_UUDECODE(p[1])); - n = UUDECODE(*p++) << 18; - n |= UUDECODE(*p++) << 12; - fputc(n >> 16, out); - --bytes; - } - if (bytes > 0) { - assert(VALID_UUDECODE(p[0])); - n |= UUDECODE(*p++) << 6; - fputc((n >> 8) & 0xFF, out); - --bytes; - } - if (bytes > 0) { - assert(VALID_UUDECODE(p[0])); - n |= UUDECODE(*p++); - fputc(n & 0xFF, out); - --bytes; - } - } - } - fclose(out); -done: - fclose(in); -} - -void -copy_reference_file(const char *name) -{ - char buff[1024]; - FILE *in, *out; - size_t rbytes; - - sprintf(buff, "%s/%s", refdir, name); - in = fopen(buff, "rb"); - failure("Couldn't open reference file %s", buff); - assert(in != NULL); - if (in == NULL) - return; - /* Now, decode the rest and write it. */ - /* Not a lot of error checking here; the input better be right. */ - out = fopen(name, "wb"); - while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) { - if (fwrite(buff, 1, rbytes, out) != rbytes) { - logprintf("Error: fwrite\n"); - break; - } - } - fclose(out); - fclose(in); -} - -int -is_LargeInode(const char *file) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - BY_HANDLE_FILE_INFORMATION bhfi; - int r; - - r = my_GetFileInformationByName(file, &bhfi); - if (r != 0) - return (0); - return (bhfi.nFileIndexHigh & 0x0000FFFFUL); -#else - struct stat st; - int64_t ino; - - if (stat(file, &st) < 0) - return (0); - ino = (int64_t)st.st_ino; - return (ino > 0xffffffff); -#endif -} - -void -extract_reference_files(const char **names) -{ - while (names && *names) - extract_reference_file(*names++); -} - -/* - * - * TEST management - * - */ - -/* - * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has - * a line like - * DEFINE_TEST(test_function) - * for each test. - */ - -/* Use "list.h" to declare all of the test functions. */ -#undef DEFINE_TEST -#define DEFINE_TEST(name) void name(void); -#include "list.h" - -/* Use "list.h" to create a list of all tests (functions and names). */ -#undef DEFINE_TEST -#define DEFINE_TEST(n) { n, #n, 0 }, -struct test_list_t tests[] = { - #include "list.h" -}; - -/* - * Summarize repeated failures in the just-completed test. - */ -static void -test_summarize(int failed, int skips_num) -{ - unsigned int i; - - switch (verbosity) { - case VERBOSITY_SUMMARY_ONLY: - printf(failed ? "E" : "."); - fflush(stdout); - break; - case VERBOSITY_PASSFAIL: - printf(failed ? "FAIL\n" : skips_num ? "ok (S)\n" : "ok\n"); - break; - } - - log_console = (verbosity == VERBOSITY_LIGHT_REPORT); - - for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) { - if (failed_lines[i].count > 1 && !failed_lines[i].skip) - logprintf("%s:%d: Summary: Failed %d times\n", - failed_filename, i, failed_lines[i].count); - } - /* Clear the failure history for the next file. */ - failed_filename = NULL; - memset(failed_lines, 0, sizeof(failed_lines)); -} - -/* - * Actually run a single test, with appropriate setup and cleanup. - */ -static int -test_run(int i, const char *tmpdir) -{ - char workdir[1024]; - char logfilename[64]; - int failures_before = failures; - int skips_before = skips; - int oldumask; - - switch (verbosity) { - case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */ - break; - case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */ - printf("%3d: %-64s", i, tests[i].name); - fflush(stdout); - break; - default: /* Title of test, details will follow */ - printf("%3d: %s\n", i, tests[i].name); - } - - /* Chdir to the top-level work directory. */ - if (!assertChdir(tmpdir)) { - fprintf(stderr, - "ERROR: Can't chdir to top work dir %s\n", tmpdir); - exit(1); - } - /* Create a log file for this test. */ - sprintf(logfilename, "%s.log", tests[i].name); - logfile = fopen(logfilename, "w"); - fprintf(logfile, "%s\n\n", tests[i].name); - /* Chdir() to a work dir for this specific test. */ - snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name); - testworkdir = workdir; - if (!assertMakeDir(testworkdir, 0755) - || !assertChdir(testworkdir)) { - fprintf(stderr, - "ERROR: Can't chdir to work dir %s\n", testworkdir); - exit(1); - } - /* Explicitly reset the locale before each test. */ - setlocale(LC_ALL, "C"); - /* Record the umask before we run the test. */ - umask(oldumask = umask(0)); - /* - * Run the actual test. - */ - (*tests[i].func)(); - /* - * Clean up and report afterwards. - */ - testworkdir = NULL; - /* Restore umask */ - umask(oldumask); - /* Reset locale. */ - setlocale(LC_ALL, "C"); - /* Reset directory. */ - if (!assertChdir(tmpdir)) { - fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n", - tmpdir); - exit(1); - } - /* Report per-test summaries. */ - tests[i].failures = failures - failures_before; - test_summarize(tests[i].failures, skips - skips_before); - /* Close the per-test log file. */ - fclose(logfile); - logfile = NULL; - /* If there were no failures, we can remove the work dir and logfile. */ - if (tests[i].failures == 0) { - if (!keep_temp_files && assertChdir(tmpdir)) { -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure not to leave empty directories. - * Sometimes a processing of closing files used by tests - * is not done, then rmdir will be failed and it will - * leave a empty test directory. So we should wait a few - * seconds and retry rmdir. */ - int r, t; - for (t = 0; t < 10; t++) { - if (t > 0) - Sleep(1000); - r = systemf("rmdir /S /Q %s", tests[i].name); - if (r == 0) - break; - } - systemf("del %s", logfilename); -#else - systemf("rm -rf %s", tests[i].name); - systemf("rm %s", logfilename); -#endif - } - } - /* Return appropriate status. */ - return (tests[i].failures); -} - -/* - * - * - * MAIN and support routines. - * - * - */ - -static void -usage(const char *program) -{ - static const int limit = sizeof(tests) / sizeof(tests[0]); - int i; - - printf("Usage: %s [options] <test> <test> ...\n", program); - printf("Default is to run all tests.\n"); - printf("Otherwise, specify the numbers of the tests you wish to run.\n"); - printf("Options:\n"); - printf(" -d Dump core after any failure, for debugging.\n"); - printf(" -k Keep all temp files.\n"); - printf(" Default: temp files for successful tests deleted.\n"); -#ifdef PROGRAM - printf(" -p <path> Path to executable to be tested.\n"); - printf(" Default: path taken from " ENVBASE " environment variable.\n"); -#endif - printf(" -q Quiet.\n"); - printf(" -r <dir> Path to dir containing reference files.\n"); - printf(" Default: Current directory.\n"); - printf(" -u Keep running specifies tests until one fails.\n"); - printf(" -v Verbose.\n"); - printf("Available tests:\n"); - for (i = 0; i < limit; i++) - printf(" %d: %s\n", i, tests[i].name); - exit(1); -} - -static char * -get_refdir(const char *d) -{ - size_t tried_size, buff_size; - char *buff, *tried, *pwd = NULL, *p = NULL; - -#ifdef PATH_MAX - buff_size = PATH_MAX; -#else - buff_size = 8192; -#endif - buff = calloc(buff_size, 1); - if (buff == NULL) { - fprintf(stderr, "Unable to allocate memory\n"); - exit(1); - } - - /* Allocate a buffer to hold the various directories we checked. */ - tried_size = buff_size * 2; - tried = calloc(tried_size, 1); - if (tried == NULL) { - fprintf(stderr, "Unable to allocate memory\n"); - exit(1); - } - - /* If a dir was specified, try that */ - if (d != NULL) { - pwd = NULL; - snprintf(buff, buff_size, "%s", d); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - goto failure; - } - - /* Get the current dir. */ -#ifdef PATH_MAX - pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ -#else - pwd = getcwd(NULL, 0); -#endif - while (pwd[strlen(pwd) - 1] == '\n') - pwd[strlen(pwd) - 1] = '\0'; - - /* Look for a known file. */ - snprintf(buff, buff_size, "%s", pwd); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - - snprintf(buff, buff_size, "%s/test", pwd); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - -#if defined(LIBRARY) - snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY); -#else - snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM); -#endif - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - -#if defined(PROGRAM_ALIAS) - snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); -#endif - - if (memcmp(pwd, "/usr/obj", 8) == 0) { - snprintf(buff, buff_size, "%s", pwd + 8); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - - snprintf(buff, buff_size, "%s/test", pwd + 8); - p = slurpfile(NULL, "%s/%s", buff, KNOWNREF); - if (p != NULL) goto success; - strncat(tried, buff, tried_size - strlen(tried) - 1); - strncat(tried, "\n", tried_size - strlen(tried) - 1); - } - -failure: - printf("Unable to locate known reference file %s\n", KNOWNREF); - printf(" Checked following directories:\n%s\n", tried); - printf("Use -r option to specify full path to reference directory\n"); -#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) - DebugBreak(); -#endif - exit(1); - -success: - free(p); - free(pwd); - free(tried); - - /* Copy result into a fresh buffer to reduce memory usage. */ - p = strdup(buff); - free(buff); - return p; -} - -int -main(int argc, char **argv) -{ - static const int limit = sizeof(tests) / sizeof(tests[0]); - int test_set[sizeof(tests) / sizeof(tests[0])]; - int i = 0, j = 0, tests_run = 0, tests_failed = 0, option; - time_t now; - char *refdir_alloc = NULL; - const char *progname; - char **saved_argv; - const char *tmp, *option_arg, *p; - char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL; - char tmpdir_timestamp[256]; - - (void)argc; /* UNUSED */ - - /* Get the current dir. */ -#ifdef PATH_MAX - pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */ -#else - pwd = getcwd(NULL, 0); -#endif - while (pwd[strlen(pwd) - 1] == '\n') - pwd[strlen(pwd) - 1] = '\0'; - -#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__) - /* To stop to run the default invalid parameter handler. */ - _set_invalid_parameter_handler(invalid_parameter_handler); - /* Disable annoying assertion message box. */ - _CrtSetReportMode(_CRT_ASSERT, 0); -#endif - - /* - * Name of this program, used to build root of our temp directory - * tree. - */ - progname = p = argv[0]; - if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL) - { - fprintf(stderr, "ERROR: Out of memory."); - exit(1); - } - strcpy(testprogdir, progname); - while (*p != '\0') { - /* Support \ or / dir separators for Windows compat. */ - if (*p == '/' || *p == '\\') - { - progname = p + 1; - i = j; - } - ++p; - j++; - } - testprogdir[i] = '\0'; -#if defined(_WIN32) && !defined(__CYGWIN__) - if (testprogdir[0] != '/' && testprogdir[0] != '\\' && - !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') || - (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) && - testprogdir[1] == ':' && - (testprogdir[2] == '/' || testprogdir[2] == '\\'))) -#else - if (testprogdir[0] != '/') -#endif - { - /* Fixup path for relative directories. */ - if ((testprogdir = (char *)realloc(testprogdir, - strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL) - { - fprintf(stderr, "ERROR: Out of memory."); - exit(1); - } - memmove(testprogdir + strlen(pwd) + 1, testprogdir, - strlen(testprogdir) + 1); - memcpy(testprogdir, pwd, strlen(pwd)); - testprogdir[strlen(pwd)] = '/'; - } - -#ifdef PROGRAM - /* Get the target program from environment, if available. */ - testprogfile = getenv(ENVBASE); -#endif - - if (getenv("TMPDIR") != NULL) - tmp = getenv("TMPDIR"); - else if (getenv("TMP") != NULL) - tmp = getenv("TMP"); - else if (getenv("TEMP") != NULL) - tmp = getenv("TEMP"); - else if (getenv("TEMPDIR") != NULL) - tmp = getenv("TEMPDIR"); - else - tmp = "/tmp"; - - /* Allow -d to be controlled through the environment. */ - if (getenv(ENVBASE "_DEBUG") != NULL) - dump_on_failure = 1; - - /* Allow -v to be controlled through the environment. */ - if (getenv("_VERBOSITY_LEVEL") != NULL) - { - vlevel = getenv("_VERBOSITY_LEVEL"); - verbosity = atoi(vlevel); - if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL) - { - /* Unsupported verbosity levels are silently ignored */ - vlevel = NULL; - verbosity = VERBOSITY_PASSFAIL; - } - } - - /* Get the directory holding test files from environment. */ - refdir = getenv(ENVBASE "_TEST_FILES"); - - /* - * Parse options, without using getopt(), which isn't available - * on all platforms. - */ - ++argv; /* Skip program name */ - while (*argv != NULL) { - if (**argv != '-') - break; - p = *argv++; - ++p; /* Skip '-' */ - while (*p != '\0') { - option = *p++; - option_arg = NULL; - /* If 'opt' takes an argument, parse that. */ - if (option == 'p' || option == 'r') { - if (*p != '\0') - option_arg = p; - else if (*argv == NULL) { - fprintf(stderr, - "Option -%c requires argument.\n", - option); - usage(progname); - } else - option_arg = *argv++; - p = ""; /* End of this option word. */ - } - - /* Now, handle the option. */ - switch (option) { - case 'd': - dump_on_failure = 1; - break; - case 'k': - keep_temp_files = 1; - break; - case 'p': -#ifdef PROGRAM - testprogfile = option_arg; -#else - fprintf(stderr, "-p option not permitted\n"); - usage(progname); -#endif - break; - case 'q': - if (!vlevel) - verbosity--; - break; - case 'r': - refdir = option_arg; - break; - case 'u': - until_failure++; - break; - case 'v': - if (!vlevel) - verbosity++; - break; - default: - fprintf(stderr, "Unrecognized option '%c'\n", - option); - usage(progname); - } - } - } - - /* - * Sanity-check that our options make sense. - */ -#ifdef PROGRAM - if (testprogfile == NULL) - { - if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 + - strlen(PROGRAM) + 1)) == NULL) - { - fprintf(stderr, "ERROR: Out of memory."); - exit(1); - } - strcpy(tmp2, testprogdir); - strcat(tmp2, "/"); - strcat(tmp2, PROGRAM); - testprogfile = tmp2; - } - - { - char *testprg; -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Command.com sometimes rejects '/' separators. */ - testprg = strdup(testprogfile); - for (i = 0; testprg[i] != '\0'; i++) { - if (testprg[i] == '/') - testprg[i] = '\\'; - } - testprogfile = testprg; -#endif - /* Quote the name that gets put into shell command lines. */ - testprg = malloc(strlen(testprogfile) + 3); - strcpy(testprg, "\""); - strcat(testprg, testprogfile); - strcat(testprg, "\""); - testprog = testprg; - } -#endif - -#if !defined(_WIN32) && defined(SIGPIPE) - { /* Ignore SIGPIPE signals */ - struct sigaction sa; - sa.sa_handler = SIG_IGN; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGPIPE, &sa, NULL); - } -#endif - - /* - * Create a temp directory for the following tests. - * Include the time the tests started as part of the name, - * to make it easier to track the results of multiple tests. - */ - now = time(NULL); - for (i = 0; ; i++) { - strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp), - "%Y-%m-%dT%H.%M.%S", - localtime(&now)); - snprintf(tmpdir, sizeof(tmpdir), "%s/%s.%s-%03d", tmp, - progname, tmpdir_timestamp, i); - if (assertMakeDir(tmpdir,0755)) - break; - if (i >= 999) { - fprintf(stderr, - "ERROR: Unable to create temp directory %s\n", - tmpdir); - exit(1); - } - } - - /* - * If the user didn't specify a directory for locating - * reference files, try to find the reference files in - * the "usual places." - */ - refdir = refdir_alloc = get_refdir(refdir); - - /* - * Banner with basic information. - */ - printf("\n"); - printf("If tests fail or crash, details will be in:\n"); - printf(" %s\n", tmpdir); - printf("\n"); - if (verbosity > VERBOSITY_SUMMARY_ONLY) { - printf("Reference files will be read from: %s\n", refdir); -#ifdef PROGRAM - printf("Running tests on: %s\n", testprog); -#endif - printf("Exercising: "); - fflush(stdout); - printf("%s\n", EXTRA_VERSION); - } else { - printf("Running "); - fflush(stdout); - } - - /* - * Run some or all of the individual tests. - */ - saved_argv = argv; - do { - argv = saved_argv; - do { - int test_num; - - test_num = get_test_set(test_set, limit, *argv, tests); - if (test_num < 0) { - printf("*** INVALID Test %s\n", *argv); - free(refdir_alloc); - free(testprogdir); - usage(progname); - return (1); - } - for (i = 0; i < test_num; i++) { - tests_run++; - if (test_run(test_set[i], tmpdir)) { - tests_failed++; - if (until_failure) - goto finish; - } - } - if (*argv != NULL) - argv++; - } while (*argv != NULL); - } while (until_failure); - -finish: - /* Must be freed after all tests run */ - free(tmp2); - free(testprogdir); - free(pwd); - - /* - * Report summary statistics. - */ - if (verbosity > VERBOSITY_SUMMARY_ONLY) { - printf("\n"); - printf("Totals:\n"); - printf(" Tests run: %8d\n", tests_run); - printf(" Tests failed: %8d\n", tests_failed); - printf(" Assertions checked:%8d\n", assertions); - printf(" Assertions failed: %8d\n", failures); - printf(" Skips reported: %8d\n", skips); - } - if (failures) { - printf("\n"); - printf("Failing tests:\n"); - for (i = 0; i < limit; ++i) { - if (tests[i].failures) - printf(" %d: %s (%d failures)\n", i, - tests[i].name, tests[i].failures); - } - printf("\n"); - printf("Details for failing tests: %s\n", tmpdir); - printf("\n"); - } else { - if (verbosity == VERBOSITY_SUMMARY_ONLY) - printf("\n"); - printf("%d tests passed, no failures\n", tests_run); - } - - free(refdir_alloc); - - /* If the final tmpdir is empty, we can remove it. */ - /* This should be the usual case when all tests succeed. */ - assertChdir(".."); - rmdir(tmpdir); - - return (tests_failed ? 1 : 0); -} diff --git a/tar/test/test.h b/tar/test/test.h index 3a23a05a..1e1bee80 100644 --- a/tar/test/test.h +++ b/tar/test/test.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2006 Tim Kientzle + * Copyright (c) 2003-2017 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,333 +22,19 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/usr.bin/tar/test/test.h,v 1.4 2008/08/21 07:04:57 kientzle Exp $ + * $FreeBSD$ */ /* Every test program should #include "test.h" as the first thing. */ -/* - * The goal of this file (and the matching test.c) is to - * simplify the very repetitive test-*.c test programs. - */ -#if defined(HAVE_CONFIG_H) -/* Most POSIX platforms use the 'configure' script to build config.h */ -#include "config.h" -#elif defined(__FreeBSD__) -/* Building as part of FreeBSD system requires a pre-built config.h. */ -#include "config_freebsd.h" -#elif defined(_WIN32) && !defined(__CYGWIN__) -/* Win32 can't run the 'configure' script. */ -#include "config_windows.h" -#else -/* Warn if the library hasn't been (automatically or manually) configured. */ -#error Oops: No config.h and no pre-built configuration in test.h. -#endif - -#include <sys/types.h> /* Windows requires this before sys/stat.h */ -#include <sys/stat.h> - -#if HAVE_DIRENT_H -#include <dirent.h> -#endif -#ifdef HAVE_DIRECT_H -#include <direct.h> -#define dirent direct -#endif -#include <errno.h> -#include <fcntl.h> -#ifdef HAVE_IO_H -#include <io.h> -#endif -#ifdef HAVE_STDINT_H -#include <stdint.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <time.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <wchar.h> -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif - -/* - * System-specific tweaks. We really want to minimize these - * as much as possible, since they make it harder to understand - * the mainline code. - */ - -/* Windows (including Visual Studio and MinGW but not Cygwin) */ -#if defined(_WIN32) && !defined(__CYGWIN__) -#if !defined(__BORLANDC__) -#undef chdir -#define chdir _chdir -#define strdup _strdup -#endif -#endif - -/* Visual Studio */ -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf sprintf_s -#endif - -#if defined(__BORLANDC__) -#pragma warn -8068 /* Constant out of range in comparison. */ -#endif - -/* Haiku OS and QNX */ -#if defined(__HAIKU__) || defined(__QNXNTO__) -/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */ -#include <stdint.h> -#endif - -/* Get a real definition for __FBSDID if we can */ -#if HAVE_SYS_CDEFS_H -#include <sys/cdefs.h> -#endif - -/* If not, define it so as to avoid dangling semicolons. */ -#ifndef __FBSDID -#define __FBSDID(a) struct _undefined_hack -#endif - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -/* - * Redefine DEFINE_TEST for use in defining the test functions. - */ -#undef DEFINE_TEST -#define DEFINE_TEST(name) void name(void); void name(void) - -/* An implementation of the standard assert() macro */ -#define assert(e) assertion_assert(__FILE__, __LINE__, (e), #e, NULL) -/* chdir() and error if it fails */ -#define assertChdir(path) \ - assertion_chdir(__FILE__, __LINE__, path) -/* Assert two integers are the same. Reports value of each one if not. */ -#define assertEqualInt(v1,v2) \ - assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) -/* Assert two strings are the same. Reports value of each one if not. */ -#define assertEqualString(v1,v2) \ - assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0) -#define assertEqualUTF8String(v1,v2) \ - assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1) -/* As above, but v1 and v2 are wchar_t * */ -#define assertEqualWString(v1,v2) \ - assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) -/* As above, but raw blocks of bytes. */ -#define assertEqualMem(v1, v2, l) \ - assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL) -/* Assert that memory is full of a specified byte */ -#define assertMemoryFilledWith(v1, l, b) \ - assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL) -/* Assert two files are the same. */ -#define assertEqualFile(f1, f2) \ - assertion_equal_file(__FILE__, __LINE__, (f1), (f2)) -/* Assert that a file is empty. */ -#define assertEmptyFile(pathname) \ - assertion_empty_file(__FILE__, __LINE__, (pathname)) -/* Assert that a file is not empty. */ -#define assertNonEmptyFile(pathname) \ - assertion_non_empty_file(__FILE__, __LINE__, (pathname)) -#define assertFileAtime(pathname, sec, nsec) \ - assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileAtimeRecent(pathname) \ - assertion_file_atime_recent(__FILE__, __LINE__, pathname) -#define assertFileBirthtime(pathname, sec, nsec) \ - assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileBirthtimeRecent(pathname) \ - assertion_file_birthtime_recent(__FILE__, __LINE__, pathname) -/* Assert that a file exists; supports printf-style arguments. */ -#define assertFileExists(pathname) \ - assertion_file_exists(__FILE__, __LINE__, pathname) -/* Assert that a file exists. */ -#define assertFileNotExists(pathname) \ - assertion_file_not_exists(__FILE__, __LINE__, pathname) -/* Assert that file contents match a string. */ -#define assertFileContents(data, data_size, pathname) \ - assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname) -/* Verify that a file does not contain invalid strings */ -#define assertFileContainsNoInvalidStrings(pathname, strings) \ - assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings) -#define assertFileMtime(pathname, sec, nsec) \ - assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec) -#define assertFileMtimeRecent(pathname) \ - assertion_file_mtime_recent(__FILE__, __LINE__, pathname) -#define assertFileNLinks(pathname, nlinks) \ - assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks) -#define assertFileSize(pathname, size) \ - assertion_file_size(__FILE__, __LINE__, pathname, size) -#define assertFileMode(pathname, mode) \ - assertion_file_mode(__FILE__, __LINE__, pathname, mode) -#define assertTextFileContents(text, pathname) \ - assertion_text_file_contents(__FILE__, __LINE__, text, pathname) -#define assertFileContainsLinesAnyOrder(pathname, lines) \ - assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines) -#define assertIsDir(pathname, mode) \ - assertion_is_dir(__FILE__, __LINE__, pathname, mode) -#define assertIsHardlink(path1, path2) \ - assertion_is_hardlink(__FILE__, __LINE__, path1, path2) -#define assertIsNotHardlink(path1, path2) \ - assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2) -#define assertIsReg(pathname, mode) \ - assertion_is_reg(__FILE__, __LINE__, pathname, mode) -#define assertIsSymlink(pathname, contents) \ - assertion_is_symlink(__FILE__, __LINE__, pathname, contents) -/* Create a directory, report error if it fails. */ -#define assertMakeDir(dirname, mode) \ - assertion_make_dir(__FILE__, __LINE__, dirname, mode) -#define assertMakeFile(path, mode, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents) -#define assertMakeBinFile(path, mode, csize, contents) \ - assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents) -#define assertMakeHardlink(newfile, oldfile) \ - assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) -#define assertMakeSymlink(newfile, linkto) \ - assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) -#define assertNodump(path) \ - assertion_nodump(__FILE__, __LINE__, path) -#define assertUmask(mask) \ - assertion_umask(__FILE__, __LINE__, mask) -#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \ - assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec) - -/* - * This would be simple with C99 variadic macros, but I don't want to - * require that. Instead, I insert a function call before each - * skipping() call to pass the file and line information down. Crude, - * but effective. - */ -#define skipping \ - skipping_setup(__FILE__, __LINE__);test_skipping - -/* Function declarations. These are defined in test_utility.c. */ -void failure(const char *fmt, ...); -int assertion_assert(const char *, int, int, const char *, void *); -int assertion_chdir(const char *, int, const char *); -int assertion_empty_file(const char *, int, const char *); -int assertion_equal_file(const char *, int, const char *, const char *); -int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *); -int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *); -int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *); -int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int); -int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); -int assertion_file_atime(const char *, int, const char *, long, long); -int assertion_file_atime_recent(const char *, int, const char *); -int assertion_file_birthtime(const char *, int, const char *, long, long); -int assertion_file_birthtime_recent(const char *, int, const char *); -int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **); -int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **); -int assertion_file_contents(const char *, int, const void *, int, const char *); -int assertion_file_exists(const char *, int, const char *); -int assertion_file_mode(const char *, int, const char *, int); -int assertion_file_mtime(const char *, int, const char *, long, long); -int assertion_file_mtime_recent(const char *, int, const char *); -int assertion_file_nlinks(const char *, int, const char *, int); -int assertion_file_not_exists(const char *, int, const char *); -int assertion_file_size(const char *, int, const char *, long); -int assertion_is_dir(const char *, int, const char *, int); -int assertion_is_hardlink(const char *, int, const char *, const char *); -int assertion_is_not_hardlink(const char *, int, const char *, const char *); -int assertion_is_reg(const char *, int, const char *, int); -int assertion_is_symlink(const char *, int, const char *, const char *); -int assertion_make_dir(const char *, int, const char *, int); -int assertion_make_file(const char *, int, const char *, int, int, const void *); -int assertion_make_hardlink(const char *, int, const char *newpath, const char *); -int assertion_make_symlink(const char *, int, const char *newpath, const char *); -int assertion_nodump(const char *, int, const char *); -int assertion_non_empty_file(const char *, int, const char *); -int assertion_text_file_contents(const char *, int, const char *buff, const char *f); -int assertion_umask(const char *, int, int); -int assertion_utimes(const char *, int, const char *, long, long, long, long ); - -void skipping_setup(const char *, int); -void test_skipping(const char *fmt, ...); - -/* Like sprintf, then system() */ -int systemf(const char * fmt, ...); - -/* Delay until time() returns a value after this. */ -void sleepUntilAfter(time_t); - -/* Return true if this platform can create symlinks. */ -int canSymlink(void); - -/* Return true if this platform can run the "bzip2" program. */ -int canBzip2(void); - -/* Return true if this platform can run the "grzip" program. */ -int canGrzip(void); - -/* Return true if this platform can run the "gzip" program. */ -int canGzip(void); - -/* Return true if this platform can run the specified command. */ -int canRunCommand(const char *); - -/* Return true if this platform can run the "lrzip" program. */ -int canLrzip(void); - -/* Return true if this platform can run the "lz4" program. */ -int canLz4(void); - -/* Return true if this platform can run the "lzip" program. */ -int canLzip(void); - -/* Return true if this platform can run the "lzma" program. */ -int canLzma(void); - -/* Return true if this platform can run the "lzop" program. */ -int canLzop(void); - -/* Return true if this platform can run the "xz" program. */ -int canXz(void); - -/* Return true if this filesystem can handle nodump flags. */ -int canNodump(void); - -/* Return true if the file has large i-node number(>0xffffffff). */ -int is_LargeInode(const char *); - -/* Suck file into string allocated via malloc(). Call free() when done. */ -/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */ -char *slurpfile(size_t *, const char *fmt, ...); - -/* Dump block of bytes to a file. */ -void dumpfile(const char *filename, void *, size_t); - -/* Extracts named reference file to the current directory. */ -void extract_reference_file(const char *); -/* Copies named reference file to the current directory. */ -void copy_reference_file(const char *); - -/* Extracts a list of files to the current directory. - * List must be NULL terminated. - */ -void extract_reference_files(const char **); - -/* Subtract umask from mode */ -mode_t umasked(mode_t expected_mode); - -/* Path to working directory for current test */ -extern const char *testworkdir; - -/* - * Special interfaces for program test harness. - */ - -/* Pathname of exe to be tested. */ -extern const char *testprogfile; -/* Name of exe to use in printf-formatted command strings. */ -/* On Windows, this includes leading/trailing quotes. */ -extern const char *testprog; - -#ifdef USE_DMALLOC -#include <dmalloc.h> -#endif +#define KNOWNREF "test_patterns_2.tar.uu" +#define ENVBASE "BSDTAR" /* Prefix for environment variables. */ +#define PROGRAM "bsdtar" /* Name of program being tested. */ +#define PROGRAM_ALIAS "tar" /* Generic alias for program */ +#undef LIBRARY /* Not testing a library. */ +#undef EXTRA_DUMP /* How to dump extra data */ +#undef EXTRA_ERRNO /* How to dump errno */ +/* How to generate extra version info. */ +#define EXTRA_VERSION (systemf("%s --version", testprog) ? "" : "") + +#include "test_common.h" diff --git a/tar/test/test_version.c b/tar/test/test_version.c index d3d9a038..1b896c0c 100644 --- a/tar/test/test_version.c +++ b/tar/test/test_version.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2003-2017 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,14 +23,11 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_version.c,v 1.2 2008/05/26 17:10:10 kientzle Exp $"); /* * Test that --version option works and generates reasonable output. */ -#include "lib/version.h" - DEFINE_TEST(test_version) { assertVersion(testprog, "bsdtar"); diff --git a/test_utils/lib/version.c b/test_utils/lib/version.c deleted file mode 100644 index 8075678c..00000000 --- a/test_utils/lib/version.c +++ /dev/null @@ -1,132 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "test/test.h" -#include "lib/version.h" - -static void assert_version_id(char **qq, size_t *ss) -{ - char *q = *qq; - size_t s = *ss; - - /* Version number is a series of digits and periods. */ - while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) { - ++q; - --s; - } - - if (q[0] == 'd' && q[1] == 'e' && q[2] == 'v') { - q += 3; - s -= 3; - } - - /* Skip a single trailing a,b,c, or d. */ - if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd') - ++q; - - /* Version number terminated by space. */ - failure("No space after version: ``%s''", q); - assert(s > 1); - failure("No space after version: ``%s''", q); - assert(*q == ' '); - - ++q; --s; - - *qq = q; - *ss = s; -} - -void assertVersion(const char *prog, const char *base) -{ - int r; - char *p, *q; - size_t s; - unsigned int prog_len = strlen(base); - - r = systemf("%s --version >version.stdout 2>version.stderr", prog); - if (r != 0) - r = systemf("%s -W version >version.stdout 2>version.stderr", - prog); - - failure("Unable to run either %s --version or %s -W version", - prog, prog); - if (!assert(r == 0)) - return; - - /* --version should generate nothing to stdout. */ - assertEmptyFile("version.stderr"); - - /* Verify format of version message. */ - q = p = slurpfile(&s, "version.stdout"); - - /* Version message should start with name of program, then space. */ - assert(s > prog_len + 1); - - failure("Version must start with '%s': ``%s''", base, p); - if (!assertEqualMem(q, base, prog_len)) - goto done; - - q += prog_len; s -= prog_len; - - assert(*q == ' '); - q++; s--; - - assert_version_id(&q, &s); - - /* Separator. */ - failure("No `-' between program name and versions: ``%s''", p); - assertEqualMem(q, "- ", 2); - q += 2; s -= 2; - - failure("Not long enough for libarchive version: ``%s''", p); - assert(s > 11); - - failure("Libarchive version must start with `libarchive': ``%s''", p); - assertEqualMem(q, "libarchive ", 11); - - q += 11; s -= 11; - - assert_version_id(&q, &s); - - - /* Skip arbitrary third-party version numbers. */ - while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' || isalnum(*q))) { - ++q; - --s; - } - - /* All terminated by end-of-line. */ - assert(s >= 1); - - /* Skip an optional CR character (e.g., Windows) */ - failure("Version output must end with \\n or \\r\\n"); - - if (*q == '\r') { ++q; --s; } - assertEqualMem(q, "\n", 1); - -done: - free(p); - -} diff --git a/test_utils/lib/version.h b/test_utils/lib/version.h deleted file mode 100644 index 3a7ae333..00000000 --- a/test_utils/lib/version.h +++ /dev/null @@ -1,31 +0,0 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _TESTS_LIB_VERSION_H -#define _TESTS_LIB_VERSION_H - -void assertVersion(const char *prog, const char *base); - -#endif diff --git a/test_utils/test_common.h b/test_utils/test_common.h new file mode 100644 index 00000000..12702773 --- /dev/null +++ b/test_utils/test_common.h @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2003-2017 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef TEST_COMMON_H +#define TEST_COMMON_H + +/* + * The goal of this file (and the matching test.c) is to + * simplify the very repetitive test-*.c test programs. + */ +#if defined(HAVE_CONFIG_H) +/* Most POSIX platforms use the 'configure' script to build config.h */ +#include "config.h" +#elif defined(__FreeBSD__) +/* Building as part of FreeBSD system requires a pre-built config.h. */ +#include "config_freebsd.h" +#elif defined(_WIN32) && !defined(__CYGWIN__) +/* Win32 can't run the 'configure' script. */ +#include "config_windows.h" +#else +/* Warn if the library hasn't been (automatically or manually) configured. */ +#error Oops: No config.h and no pre-built configuration in test.h. +#endif + +#include <sys/types.h> /* Windows requires this before sys/stat.h */ +#include <sys/stat.h> + +#if HAVE_DIRENT_H +#include <dirent.h> +#endif +#ifdef HAVE_DIRECT_H +#include <direct.h> +#define dirent direct +#endif +#include <errno.h> +#include <fcntl.h> +#ifdef HAVE_IO_H +#include <io.h> +#endif +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <wchar.h> +#ifdef HAVE_WINDOWS_H +#include <windows.h> +#endif + +/* + * System-specific tweaks. We really want to minimize these + * as much as possible, since they make it harder to understand + * the mainline code. + */ + +/* Windows (including Visual Studio and MinGW but not Cygwin) */ +#if defined(_WIN32) && !defined(__CYGWIN__) +#if !defined(__BORLANDC__) +#undef chdir +#define chdir _chdir +#define strdup _strdup +#endif +#endif + +/* Visual Studio */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf sprintf_s +#endif + +#if defined(__BORLANDC__) +#pragma warn -8068 /* Constant out of range in comparison. */ +#endif + +/* Haiku OS and QNX */ +#if defined(__HAIKU__) || defined(__QNXNTO__) +/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */ +#include <stdint.h> +#endif + +/* Get a real definition for __FBSDID if we can */ +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif + +/* If not, define it so as to avoid dangling semicolons. */ +#ifndef __FBSDID +#define __FBSDID(a) struct _undefined_hack +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* + * If this platform has <sys/acl.h>, acl_create(), acl_init(), + * acl_set_file(), and ACL_USER, we assume it has the rest of the + * POSIX.1e draft functions used in archive_read_extract.c. + */ +#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE +#if HAVE_ACL_USER +#define HAVE_POSIX_ACL 1 +#elif HAVE_ACL_TYPE_EXTENDED +#define HAVE_DARWIN_ACL 1 +#endif +#endif + +/* + * If this platform has <sys/acl.h>, acl_get(), facl_get(), acl_set(), + * facl_set() and types aclent_t and ace_t it uses Solaris-style ACL functions + */ +#if HAVE_SYS_ACL_H && HAVE_ACL_GET && HAVE_FACL_GET && HAVE_ACL_SET && HAVE_FACL_SET && HAVE_ACLENT_T && HAVE_ACE_T +#define HAVE_SUN_ACL 1 +#endif + +/* Define if platform supports NFSv4 ACLs */ +#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL +#define HAVE_NFS4_ACL 1 +#endif + +/* + * Redefine DEFINE_TEST for use in defining the test functions. + */ +#undef DEFINE_TEST +#define DEFINE_TEST(name) void name(void); void name(void) + +/* An implementation of the standard assert() macro */ +#define assert(e) assertion_assert(__FILE__, __LINE__, (e), #e, NULL) +/* chdir() and error if it fails */ +#define assertChdir(path) \ + assertion_chdir(__FILE__, __LINE__, path) +/* Assert two integers are the same. Reports value of each one if not. */ +#define assertEqualInt(v1,v2) \ + assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) +/* Assert two strings are the same. Reports value of each one if not. */ +#define assertEqualString(v1,v2) \ + assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0) +#define assertEqualUTF8String(v1,v2) \ + assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1) +/* As above, but v1 and v2 are wchar_t * */ +#define assertEqualWString(v1,v2) \ + assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) +/* As above, but raw blocks of bytes. */ +#define assertEqualMem(v1, v2, l) \ + assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL) +/* Assert that memory is full of a specified byte */ +#define assertMemoryFilledWith(v1, l, b) \ + assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL) +/* Assert two files are the same. */ +#define assertEqualFile(f1, f2) \ + assertion_equal_file(__FILE__, __LINE__, (f1), (f2)) +/* Assert that a file is empty. */ +#define assertEmptyFile(pathname) \ + assertion_empty_file(__FILE__, __LINE__, (pathname)) +/* Assert that a file is not empty. */ +#define assertNonEmptyFile(pathname) \ + assertion_non_empty_file(__FILE__, __LINE__, (pathname)) +#define assertFileAtime(pathname, sec, nsec) \ + assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec) +#define assertFileAtimeRecent(pathname) \ + assertion_file_atime_recent(__FILE__, __LINE__, pathname) +#define assertFileBirthtime(pathname, sec, nsec) \ + assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec) +#define assertFileBirthtimeRecent(pathname) \ + assertion_file_birthtime_recent(__FILE__, __LINE__, pathname) +/* Assert that a file exists; supports printf-style arguments. */ +#define assertFileExists(pathname) \ + assertion_file_exists(__FILE__, __LINE__, pathname) +/* Assert that a file exists. */ +#define assertFileNotExists(pathname) \ + assertion_file_not_exists(__FILE__, __LINE__, pathname) +/* Assert that file contents match a string. */ +#define assertFileContents(data, data_size, pathname) \ + assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname) +/* Verify that a file does not contain invalid strings */ +#define assertFileContainsNoInvalidStrings(pathname, strings) \ + assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings) +#define assertFileMtime(pathname, sec, nsec) \ + assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec) +#define assertFileMtimeRecent(pathname) \ + assertion_file_mtime_recent(__FILE__, __LINE__, pathname) +#define assertFileNLinks(pathname, nlinks) \ + assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks) +#define assertFileSize(pathname, size) \ + assertion_file_size(__FILE__, __LINE__, pathname, size) +#define assertFileMode(pathname, mode) \ + assertion_file_mode(__FILE__, __LINE__, pathname, mode) +#define assertTextFileContents(text, pathname) \ + assertion_text_file_contents(__FILE__, __LINE__, text, pathname) +#define assertFileContainsLinesAnyOrder(pathname, lines) \ + assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines) +#define assertIsDir(pathname, mode) \ + assertion_is_dir(__FILE__, __LINE__, pathname, mode) +#define assertIsHardlink(path1, path2) \ + assertion_is_hardlink(__FILE__, __LINE__, path1, path2) +#define assertIsNotHardlink(path1, path2) \ + assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2) +#define assertIsReg(pathname, mode) \ + assertion_is_reg(__FILE__, __LINE__, pathname, mode) +#define assertIsSymlink(pathname, contents) \ + assertion_is_symlink(__FILE__, __LINE__, pathname, contents) +/* Create a directory, report error if it fails. */ +#define assertMakeDir(dirname, mode) \ + assertion_make_dir(__FILE__, __LINE__, dirname, mode) +#define assertMakeFile(path, mode, contents) \ + assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents) +#define assertMakeBinFile(path, mode, csize, contents) \ + assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents) +#define assertMakeHardlink(newfile, oldfile) \ + assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile) +#define assertMakeSymlink(newfile, linkto) \ + assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) +#define assertNodump(path) \ + assertion_nodump(__FILE__, __LINE__, path) +#define assertUmask(mask) \ + assertion_umask(__FILE__, __LINE__, mask) +#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \ + assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec) + +/* + * This would be simple with C99 variadic macros, but I don't want to + * require that. Instead, I insert a function call before each + * skipping() call to pass the file and line information down. Crude, + * but effective. + */ +#define skipping \ + skipping_setup(__FILE__, __LINE__);test_skipping + +/* Function declarations. These are defined in test_utility.c. */ +void failure(const char *fmt, ...); +int assertion_assert(const char *, int, int, const char *, void *); +int assertion_chdir(const char *, int, const char *); +int assertion_empty_file(const char *, int, const char *); +int assertion_equal_file(const char *, int, const char *, const char *); +int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *); +int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *); +int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *); +int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int); +int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); +int assertion_file_atime(const char *, int, const char *, long, long); +int assertion_file_atime_recent(const char *, int, const char *); +int assertion_file_birthtime(const char *, int, const char *, long, long); +int assertion_file_birthtime_recent(const char *, int, const char *); +int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **); +int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **); +int assertion_file_contents(const char *, int, const void *, int, const char *); +int assertion_file_exists(const char *, int, const char *); +int assertion_file_mode(const char *, int, const char *, int); +int assertion_file_mtime(const char *, int, const char *, long, long); +int assertion_file_mtime_recent(const char *, int, const char *); +int assertion_file_nlinks(const char *, int, const char *, int); +int assertion_file_not_exists(const char *, int, const char *); +int assertion_file_size(const char *, int, const char *, long); +int assertion_is_dir(const char *, int, const char *, int); +int assertion_is_hardlink(const char *, int, const char *, const char *); +int assertion_is_not_hardlink(const char *, int, const char *, const char *); +int assertion_is_reg(const char *, int, const char *, int); +int assertion_is_symlink(const char *, int, const char *, const char *); +int assertion_make_dir(const char *, int, const char *, int); +int assertion_make_file(const char *, int, const char *, int, int, const void *); +int assertion_make_hardlink(const char *, int, const char *newpath, const char *); +int assertion_make_symlink(const char *, int, const char *newpath, const char *); +int assertion_nodump(const char *, int, const char *); +int assertion_non_empty_file(const char *, int, const char *); +int assertion_text_file_contents(const char *, int, const char *buff, const char *f); +int assertion_umask(const char *, int, int); +int assertion_utimes(const char *, int, const char *, long, long, long, long ); +int assertion_version(const char*, int, const char *, const char *); + +void skipping_setup(const char *, int); +void test_skipping(const char *fmt, ...); + +/* Like sprintf, then system() */ +int systemf(const char * fmt, ...); + +/* Delay until time() returns a value after this. */ +void sleepUntilAfter(time_t); + +/* Return true if this platform can create symlinks. */ +int canSymlink(void); + +/* Return true if this platform can run the "bzip2" program. */ +int canBzip2(void); + +/* Return true if this platform can run the "grzip" program. */ +int canGrzip(void); + +/* Return true if this platform can run the "gzip" program. */ +int canGzip(void); + +/* Return true if this platform can run the specified command. */ +int canRunCommand(const char *); + +/* Return true if this platform can run the "lrzip" program. */ +int canLrzip(void); + +/* Return true if this platform can run the "lz4" program. */ +int canLz4(void); + +/* Return true if this platform can run the "lzip" program. */ +int canLzip(void); + +/* Return true if this platform can run the "lzma" program. */ +int canLzma(void); + +/* Return true if this platform can run the "lzop" program. */ +int canLzop(void); + +/* Return true if this platform can run the "xz" program. */ +int canXz(void); + +/* Return true if this filesystem can handle nodump flags. */ +int canNodump(void); + +/* Return true if the file has large i-node number(>0xffffffff). */ +int is_LargeInode(const char *); + +/* Suck file into string allocated via malloc(). Call free() when done. */ +/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */ +char *slurpfile(size_t *, const char *fmt, ...); + +/* Dump block of bytes to a file. */ +void dumpfile(const char *filename, void *, size_t); + +/* Extracts named reference file to the current directory. */ +void extract_reference_file(const char *); +/* Copies named reference file to the current directory. */ +void copy_reference_file(const char *); + +/* Extracts a list of files to the current directory. + * List must be NULL terminated. + */ +void extract_reference_files(const char **); + +/* Subtract umask from mode */ +mode_t umasked(mode_t expected_mode); + +/* Path to working directory for current test */ +extern const char *testworkdir; + +#ifndef PROGRAM +/* + * Special interfaces for libarchive test harness. + */ + +#include "archive.h" +#include "archive_entry.h" + +/* ACL structure */ +struct archive_test_acl_t { + int type; /* Type of ACL */ + int permset; /* Permissions for this class of users. */ + int tag; /* Owner, User, Owning group, group, other, etc. */ + int qual; /* GID or UID of user/group, depending on tag. */ + const char *name; /* Name of user/group, depending on tag. */ +}; + +/* Set ACLs */ +void archive_test_set_acls(struct archive_entry *, struct archive_test_acl_t *, + int); + +/* Compare ACLs */ +void archive_test_compare_acls(struct archive_entry *, + struct archive_test_acl_t *, int, int, int); + +/* Special customized read-from-memory interface. */ +int read_open_memory(struct archive *, const void *, size_t, size_t); +/* _minimal version exercises a slightly different set of libarchive APIs. */ +int read_open_memory_minimal(struct archive *, const void *, size_t, size_t); +/* _seek version produces a seekable file. */ +int read_open_memory_seek(struct archive *, const void *, size_t, size_t); + +/* Versions of above that accept an archive argument for additional info. */ +#define assertA(e) assertion_assert(__FILE__, __LINE__, (e), #e, (a)) +#define assertEqualIntA(a,v1,v2) \ + assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a)) +#define assertEqualStringA(a,v1,v2) \ + assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a), 0) + +#else /* defined(PROGRAM) */ +/* + * Special interfaces for program test harness. + */ + +/* Pathname of exe to be tested. */ +extern const char *testprogfile; +/* Name of exe to use in printf-formatted command strings. */ +/* On Windows, this includes leading/trailing quotes. */ +extern const char *testprog; + +void assertVersion(const char *prog, const char *base); + +#endif /* defined(PROGRAM) */ + +#ifdef USE_DMALLOC +#include <dmalloc.h> +#endif + +#endif /* TEST_COMMON_H */ diff --git a/libarchive/test/main.c b/test_utils/test_main.c index 46685f8b..615e31b0 100644 --- a/libarchive/test/main.c +++ b/test_utils/test_main.c @@ -54,22 +54,6 @@ #include <time.h> /* - * This same file is used pretty much verbatim for all test harnesses. - * - * The next few lines are the only differences. - * TODO: Move this into a separate configuration header, have all test - * suites share one copy of this file. - */ -__FBSDID("$FreeBSD: head/lib/libarchive/test/main.c 201247 2009-12-30 05:59:21Z kientzle $"); -#define KNOWNREF "test_compat_gtar_1.tar.uu" -#define ENVBASE "LIBARCHIVE" /* Prefix for environment variables. */ -#undef PROGRAM /* Testing a library, not a program. */ -#define LIBRARY "libarchive" -#define EXTRA_DUMP(x) archive_error_string((struct archive *)(x)) -#define EXTRA_ERRNO(x) archive_errno((struct archive *)(x)) -#define EXTRA_VERSION archive_version_details() - -/* * * Windows support routines * @@ -1942,6 +1926,117 @@ assertion_nodump(const char *file, int line, const char *pathname) return (1); } +#ifdef PROGRAM +static void assert_version_id(char **qq, size_t *ss) +{ + char *q = *qq; + size_t s = *ss; + + /* Version number is a series of digits and periods. */ + while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) { + ++q; + --s; + } + + if (q[0] == 'd' && q[1] == 'e' && q[2] == 'v') { + q += 3; + s -= 3; + } + + /* Skip a single trailing a,b,c, or d. */ + if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd') + ++q; + + /* Version number terminated by space. */ + failure("No space after version: ``%s''", q); + assert(s > 1); + failure("No space after version: ``%s''", q); + assert(*q == ' '); + + ++q; --s; + + *qq = q; + *ss = s; +} + + +/* + * Check program version + */ +void assertVersion(const char *prog, const char *base) +{ + int r; + char *p, *q; + size_t s; + unsigned int prog_len = strlen(base); + + r = systemf("%s --version >version.stdout 2>version.stderr", prog); + if (r != 0) + r = systemf("%s -W version >version.stdout 2>version.stderr", + prog); + + failure("Unable to run either %s --version or %s -W version", + prog, prog); + if (!assert(r == 0)) + return; + + /* --version should generate nothing to stdout. */ + assertEmptyFile("version.stderr"); + + /* Verify format of version message. */ + q = p = slurpfile(&s, "version.stdout"); + + /* Version message should start with name of program, then space. */ + assert(s > prog_len + 1); + + failure("Version must start with '%s': ``%s''", base, p); + if (!assertEqualMem(q, base, prog_len)) { + free(p); + return; + } + + q += prog_len; s -= prog_len; + + assert(*q == ' '); + q++; s--; + + assert_version_id(&q, &s); + + /* Separator. */ + failure("No `-' between program name and versions: ``%s''", p); + assertEqualMem(q, "- ", 2); + q += 2; s -= 2; + + failure("Not long enough for libarchive version: ``%s''", p); + assert(s > 11); + + failure("Libarchive version must start with `libarchive': ``%s''", p); + assertEqualMem(q, "libarchive ", 11); + + q += 11; s -= 11; + + assert_version_id(&q, &s); + + /* Skip arbitrary third-party version numbers. */ + while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' || + isalnum(*q))) { + ++q; + --s; + } + + /* All terminated by end-of-line. */ + assert(s >= 1); + + /* Skip an optional CR character (e.g., Windows) */ + failure("Version output must end with \\n or \\r\\n"); + + if (*q == '\r') { ++q; --s; } + assertEqualMem(q, "\n", 1); + + free(p); +} +#endif /* PROGRAM */ + /* * * UTILITIES for use by tests. @@ -2429,6 +2524,7 @@ extract_reference_files(const char **names) extract_reference_file(*names++); } +#ifndef PROGRAM /* Set ACLs */ void archive_test_set_acls(struct archive_entry *ae, @@ -2554,6 +2650,7 @@ archive_test_compare_acls(struct archive_entry *ae, assert(n == 0); /* Number of ACLs not matched should == 0 */ free(marker); } +#endif /* !defined(PROGRAM) */ /* * |