diff options
| -rw-r--r-- | NEWS | 14 | ||||
| -rw-r--r-- | configure.ac | 4 | ||||
| -rw-r--r-- | m4/gssapi.m4 | 3 | ||||
| -rw-r--r-- | m4/krb5.m4 | 39 | ||||
| -rw-r--r-- | m4/remctl.m4 | 2 | ||||
| -rw-r--r-- | portable/krb5-extra.c | 3 | ||||
| -rw-r--r-- | portable/krb5.h | 31 | ||||
| -rw-r--r-- | tests/portable/snprintf-t.c | 12 | ||||
| -rw-r--r-- | tests/runtests.c | 403 | ||||
| -rw-r--r-- | tests/tap/basic.c | 196 | ||||
| -rw-r--r-- | tests/tap/basic.h | 41 | ||||
| -rw-r--r-- | tests/tap/kerberos.c | 31 | ||||
| -rw-r--r-- | tests/tap/kerberos.sh | 17 | ||||
| -rw-r--r-- | tests/tap/libtap.sh | 32 | ||||
| -rw-r--r-- | tests/tap/remctl.sh | 18 | ||||
| -rw-r--r-- | tests/util/messages-t.c | 4 | ||||
| -rw-r--r-- | tests/util/xmalloc.c | 5 | ||||
| -rw-r--r-- | util/macros.h | 1 | ||||
| -rw-r--r-- | util/messages.c | 50 | ||||
| -rw-r--r-- | util/messages.h | 26 | 
20 files changed, 631 insertions, 301 deletions
| @@ -23,6 +23,20 @@ wallet 0.12 (unreleased)      Add a help command to wallet-report, which returns a summary of all      available commands. +    Update to C TAP Harness 1.5: + +    * Better reporting of fatal errors in the test suite. +    * Summarize results at the end of test execution. +    * Add tests/HOWTO from docs/writing-tests in C TAP Harness. + +    Update to rra-c-util 2.6: + +    * Fix portability to bundled Heimdal on OpenBSD. +    * Improve checking for krb5_kt_free_entry with older MIT Kerberos. +    * Fix portability for missing krb5_get_init_creds_opt_free. +    * Fix header guard for util/xwrite.h. +    * Restore default compiler configuration after GSS-API library probe. +  wallet 0.11 (2010-03-08)      When deleting an ACL on the server, verify that the ACL is not diff --git a/configure.ac b/configure.ac index 9f2d284..137e6ef 100644 --- a/configure.ac +++ b/configure.ac @@ -27,8 +27,10 @@ RRA_LIB_KRB5  RRA_LIB_KRB5_SWITCH  AC_CHECK_FUNCS([krb5_get_init_creds_opt_alloc \      krb5_get_init_creds_opt_set_default_flags \ -    krb5_kt_free_entry \      krb5_principal_get_realm]) +AC_CHECK_FUNCS([krb5_get_init_creds_opt_free], +    [RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS]) +AC_CHECK_DECLS([krb5_kt_free_entry])  AC_CHECK_MEMBERS([krb5_keytab_entry.keyblock], , , [#include <krb5.h>])  RRA_LIB_KRB5_RESTORE diff --git a/m4/gssapi.m4 b/m4/gssapi.m4 index 4b08569..0a657ff 100644 --- a/m4/gssapi.m4 +++ b/m4/gssapi.m4 @@ -57,7 +57,8 @@ AC_DEFUN([_RRA_LIB_GSSAPI_REDUCED],   AC_CHECK_LIB([gssapi_krb5], [gss_import_name], [GSSAPI_LIBS="-lgssapi_krb5"],       [AC_CHECK_LIB([gssapi], [gss_import_name], [GSSAPI_LIBS="-lgssapi"],           [AC_CHECK_LIB([gss], [gss_import_name], [GSSAPI_LIBS="-lgss"], -             [AC_MSG_ERROR([cannot find usable GSS-API library])])])])]) +             [AC_MSG_ERROR([cannot find usable GSS-API library])])])]) + RRA_LIB_GSSAPI_RESTORE])  dnl Does the appropriate library checks for GSS-API linkage when we don't  dnl have krb5-config or reduced dependencies.  libgss is used as a last @@ -2,7 +2,7 @@ dnl Find the compiler and linker flags for Kerberos v5.  dnl  dnl Finds the compiler and linker flags for linking with Kerberos v5  dnl libraries.  Provides the --with-krb5, --with-krb5-include, and -dnl --with-krb5-lib configure options to specify non-standards paths to the +dnl --with-krb5-lib configure options to specify non-standard paths to the  dnl Kerberos libraries.  Uses krb5-config where available unless reduced  dnl dependencies is requested.  dnl @@ -13,6 +13,9 @@ dnl Kerberos libraries, saving the current values first, and  dnl RRA_LIB_KRB5_RESTORE to restore those settings to before the last  dnl RRA_LIB_KRB5_SWITCH.  dnl +dnl If KRB5_CPPFLAGS, KRB5_LDFLAGS, or KRB5_LIBS are set before calling these +dnl macros, their values will be added to whatever the macros discover. +dnl  dnl Provides the RRA_LIB_KRB5_OPTIONAL macro, which should be used if Kerberos  dnl support is optional.  This macro will still always set the substitution  dnl variables, but they'll be empty unless --with-krb5 is given.  Also, @@ -25,8 +28,12 @@ dnl change library ordering in that case.  dnl  dnl Depends on RRA_ENABLE_REDUCED_DEPENDS and RRA_SET_LDFLAGS.  dnl +dnl Also provides RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS, which checks +dnl whether krb5_get_init_creds_opt_free takes one argument or two.  Defines +dnl HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS if it takes two arguments. +dnl  dnl Written by Russ Allbery <rra@stanford.edu> -dnl Copyright 2005, 2006, 2007, 2008, 2009 +dnl Copyright 2005, 2006, 2007, 2008, 2009, 2010  dnl     Board of Trustees, Leland Stanford Jr. University  dnl  dnl See LICENSE for licensing terms. @@ -99,10 +106,11 @@ AC_DEFUN([_RRA_LIB_KRB5_MANUAL],      [AC_CHECK_LIB([nsl], [socket], [LIBS="-lnsl -lsocket $LIBS"], ,          [-lsocket])])   AC_SEARCH_LIBS([crypt], [crypt]) + AC_SEARCH_LIBS([rk_simple_execve], [roken])   rra_krb5_extra="$LIBS"   LIBS="$rra_krb5_save_LIBS"   AC_CHECK_LIB([krb5], [krb5_init_context], -    [KRB5_LIBS="-lkrb5 -lasn1 -lroken -lcrypto -lcom_err $rra_krb5_extra"], +    [KRB5_LIBS="-lkrb5 -lasn1 -lcom_err -lcrypto $rra_krb5_extra"],      [AC_CHECK_LIB([krb5support], [krb5int_getspecific],          [rra_krb5_extra="-lkrb5support $rra_krb5_extra"],          [AC_CHECK_LIB([pthreads], [pthread_setspecific], @@ -125,7 +133,7 @@ AC_DEFUN([_RRA_LIB_KRB5_MANUAL],          [AS_IF([test x"$1" = xtrue],              [AC_MSG_ERROR([cannot find usable Kerberos v5 library])])],          [$rra_krb5_extra])], -    [-lasn1 -lroken -lcrypto -lcom_err $rra_krb5_extra]) +    [-lasn1 -lcom_err -lcrypto $rra_krb5_extra])   LIBS="$KRB5_LIBS $LIBS"   AC_CHECK_FUNCS([krb5_get_error_message],       [AC_CHECK_FUNCS([krb5_free_error_message])], @@ -200,9 +208,6 @@ AC_DEFUN([RRA_LIB_KRB5],  [rra_krb5_root=   rra_krb5_libdir=   rra_krb5_includedir= - KRB5_CPPFLAGS= - KRB5_LDFLAGS= - KRB5_LIBS=   AC_SUBST([KRB5_CPPFLAGS])   AC_SUBST([KRB5_LDFLAGS])   AC_SUBST([KRB5_LIBS]) @@ -230,9 +235,6 @@ AC_DEFUN([RRA_LIB_KRB5_OPTIONAL],   rra_krb5_libdir=   rra_krb5_includedir=   rra_use_kerberos= - KRB5_CPPFLAGS= - KRB5_LDFLAGS= - KRB5_LIBS=   AC_SUBST([KRB5_CPPFLAGS])   AC_SUBST([KRB5_LDFLAGS])   AC_SUBST([KRB5_LIBS]) @@ -261,3 +263,20 @@ AC_DEFUN([RRA_LIB_KRB5_OPTIONAL],           [_RRA_LIB_KRB5_INTERNAL([false])])])   AS_IF([test x"$KRB5_LIBS" != x],      [AC_DEFINE([HAVE_KERBEROS], 1, [Define to enable Kerberos features.])])]) + +dnl Check whether krb5_get_init_creds_opt_free takes one argument or two. +dnl Early Heimdal used to take a single argument.  Defines +dnl HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS if it takes two arguments. +dnl +dnl Should be called with RRA_LIB_KRB5_SWITCH active. +AC_DEFUN([RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS], +[AC_CACHE_CHECK([if krb5_get_init_creds_opt_free takes two arguments], +    [rra_cv_func_krb5_get_init_creds_opt_free_args], +    [AC_TRY_COMPILE([#include <krb5.h>], +        [krb5_get_init_creds_opt *opts; krb5_context c; +         krb5_get_init_creds_opt_free(c, opts);], +        [rra_cv_func_krb5_get_init_creds_opt_free_args=yes], +        [rra_cv_func_krb5_get_init_creds_opt_free_args=no])]) + AS_IF([test $rra_cv_func_krb5_get_init_creds_opt_free_args = yes], +    [AC_DEFINE([HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS], 1, +        [Define if krb5_get_init_creds_opt_free takes two arguments.])])]) diff --git a/m4/remctl.m4 b/m4/remctl.m4 index 8ee3c16..bb3a56f 100644 --- a/m4/remctl.m4 +++ b/m4/remctl.m4 @@ -21,7 +21,7 @@ dnl  dnl See LICENSE for licensing terms.  dnl Save the current CPPFLAGS, LDFLAGS, and LIBS settings and switch to -dnl versions that include the Kerberos v5 flags.  Used as a wrapper, with +dnl versions that include the remctl flags.  Used as a wrapper, with  dnl RRA_LIB_REMCTL_RESTORE, around tests.  AC_DEFUN([RRA_LIB_REMCTL_SWITCH],  [rra_remctl_save_CPPFLAGS="$CPPFLAGS" diff --git a/portable/krb5-extra.c b/portable/krb5-extra.c index dcddbe4..89ccbde 100644 --- a/portable/krb5-extra.c +++ b/portable/krb5-extra.c @@ -97,7 +97,8 @@ krb5_free_error_message(krb5_context ctx UNUSED, const char *msg)   * assumes that an all-zero bit pattern will create a NULL pointer.   */  krb5_error_code -krb5_get_init_creds_opt_alloc(krb5_context ctx, krb5_get_init_creds_opt **opts) +krb5_get_init_creds_opt_alloc(krb5_context ctx UNUSED, +                              krb5_get_init_creds_opt **opts)  {      *opts = calloc(1, sizeof(krb5_get_init_creds_opt));      if (*opts == NULL) diff --git a/portable/krb5.h b/portable/krb5.h index d9ef283..3b5700b 100644 --- a/portable/krb5.h +++ b/portable/krb5.h @@ -23,10 +23,17 @@  #ifndef PORTABLE_KRB5_H  #define PORTABLE_KRB5_H 1 -#include <config.h> +/* + * Allow inclusion of config.h to be skipped, since sometimes we have to use a + * stripped-down version of config.h with a different name. + */ +#ifndef CONFIG_H_INCLUDED +# include <config.h> +#endif  #include <portable/macros.h>  #include <krb5.h> +#include <stdlib.h>  BEGIN_DECLS @@ -50,27 +57,39 @@ void krb5_free_error_message(krb5_context, const char *);  #endif  /* - * Both current MIT and current Heimdal prefer _opt_alloc, but older versions - * of both require allocating your own struct and calling _opt_init. + * Both current MIT and current Heimdal prefer _opt_alloc and _opt_free, but + * older versions of both require allocating your own struct and calling + * _opt_init.   */  #ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC  krb5_error_code krb5_get_init_creds_opt_alloc(krb5_context,                                                krb5_get_init_creds_opt **);  #endif +#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE +# ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS +#  define krb5_get_init_creds_opt_free(c, o) krb5_get_init_creds_opt_free(o) +# endif +#else +# define krb5_get_init_creds_opt_free(c, o) free(o) +#endif  /* Heimdal-specific. */  #ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_DEFAULT_FLAGS  #define krb5_get_init_creds_opt_set_default_flags(c, p, r, o) /* empty */  #endif -/* Heimdal: krb5_kt_free_entry, MIT: krb5_free_keytab_entry_contents. */ -#ifndef HAVE_KRB5_KT_FREE_ENTRY +/* + * Heimdal: krb5_kt_free_entry, MIT: krb5_free_keytab_entry_contents.  We + * check for the declaration rather than the function since the function is + * present in older MIT Kerberos libraries but not prototyped. + */ +#if !HAVE_DECL_KRB5_KT_FREE_ENTRY  # define krb5_kt_free_entry(c, e) krb5_free_keytab_entry_contents((c), (e))  #endif  /*   * Heimdal provides a nice function that just returns a const char *.  On MIT, - * there's an accessor macro that returns the krb5_data pointer, wihch + * there's an accessor macro that returns the krb5_data pointer, which   * requires more work to get at the underlying char *.   */  #ifndef HAVE_KRB5_PRINCIPAL_GET_REALM diff --git a/tests/portable/snprintf-t.c b/tests/portable/snprintf-t.c index ca6ae61..fd4c228 100644 --- a/tests/portable/snprintf-t.c +++ b/tests/portable/snprintf-t.c @@ -2,7 +2,7 @@   * snprintf test suite.   *   * Written by Russ Allbery <rra@stanford.edu> - * Copyright 2009 Board of Trustees, Leland Stanford Jr. University + * Copyright 2009, 2010 Board of Trustees, Leland Stanford Jr. University   * Copyright (c) 2004, 2005, 2006   *     by Internet Systems Consortium, Inc. ("ISC")   * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, @@ -17,6 +17,12 @@  #include <tests/tap/basic.h>  /* + * Disable the requirement that format strings be literals.  We need variable + * formats for easy testing. + */ +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +/*   * Intentionally don't add the printf attribute here since we pass a   * zero-length printf format during testing and don't want warnings.   */ @@ -86,7 +92,7 @@ static unsigned long long ullong_nums[] = {  static void -test_format(bool truncate, const char *expected, int count, +test_format(bool trunc, const char *expected, int count,              const char *format, ...)  {      char buf[128]; @@ -94,7 +100,7 @@ test_format(bool truncate, const char *expected, int count,      va_list args;      va_start(args, format); -    result = test_vsnprintf(buf, truncate ? 32 : sizeof(buf), format, args); +    result = test_vsnprintf(buf, trunc ? 32 : sizeof(buf), format, args);      va_end(args);      is_string(expected, buf, "format %s, wanted %s", format, expected);      is_int(count, result, "...and output length correct"); diff --git a/tests/runtests.c b/tests/runtests.c index 1670012..ab77629 100644 --- a/tests/runtests.c +++ b/tests/runtests.c @@ -8,22 +8,41 @@   * Expects a list of executables located in the given file, one line per   * executable.  For each one, runs it as part of a test suite, reporting   * results.  Test output should start with a line containing the number of - * tests (numbered from 1 to this number), and then each line should be in the - * following format: + * tests (numbered from 1 to this number), optionally preceded by "1..", + * although that line may be given anywhere in the output.  Each additional + * line should be in the following format:   *   *      ok <number>   *      not ok <number>   *      ok <number> # skip + *      not ok <number> # todo   * - * where <number> is the number of the test.  ok indicates success, not ok - * indicates failure, and "# skip" indicates the test was skipped for some - * reason (maybe because it doesn't apply to this platform).  This is a subset - * of TAP as documented in Test::Harness::TAP, which comes with Perl. + * where <number> is the number of the test.  An optional comment is permitted + * after the number if preceded by whitespace.  ok indicates success, not ok + * indicates failure.  "# skip" and "# todo" are a special cases of a comment, + * and must start with exactly that formatting.  They indicate the test was + * skipped for some reason (maybe because it doesn't apply to this platform) + * or is testing something known to currently fail.  The text following either + * "# skip" or "# todo" and whitespace is the reason. + * + * As a special case, the first line of the output may be in the form: + * + *      1..0 # skip some reason + * + * which indicates that this entire test case should be skipped and gives a + * reason. + * + * Any other lines are ignored, although for compliance with the TAP protocol + * all lines other than the ones in the above format should be sent to + * standard error rather than standard output and start with #. + * + * This is a subset of TAP as documented in Test::Harness::TAP or + * TAP::Parser::Grammar, which comes with Perl.   *   * Any bug reports, bug fixes, and improvements are very much welcome and   * should be sent to the e-mail address below.   * - * Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009 + * Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010   *     Russ Allbery <rra@stanford.edu>   *   * Permission is hereby granted, free of charge, to any person obtaining a @@ -88,6 +107,14 @@ enum test_status {      TEST_INVALID  }; +/* Indicates the state of our plan. */ +enum plan_status { +    PLAN_INIT,                  /* Nothing seen yet. */ +    PLAN_FIRST,                 /* Plan seen before any tests. */ +    PLAN_PENDING,               /* Test seen and no plan yet. */ +    PLAN_FINAL                  /* Plan seen after some tests. */ +}; +  /* Error exit statuses for test processes. */  #define CHILDERR_DUP    100     /* Couldn't redirect stderr or stdout. */  #define CHILDERR_EXEC   101     /* Couldn't exec child process. */ @@ -97,12 +124,14 @@ enum test_status {  struct testset {      char *file;                 /* The file name of the test. */      char *path;                 /* The path to the test program. */ -    int count;                  /* Expected count of tests. */ -    int current;                /* The last seen test number. */ -    int length;                 /* The length of the last status message. */ -    int passed;                 /* Count of passing tests. */ -    int failed;                 /* Count of failing lists. */ -    int skipped;                /* Count of skipped tests (passed). */ +    enum plan_status plan;      /* The status of our plan. */ +    unsigned long count;        /* Expected count of tests. */ +    unsigned long current;      /* The last seen test number. */ +    unsigned int length;        /* The length of the last status message. */ +    unsigned long passed;       /* Count of passing tests. */ +    unsigned long failed;       /* Count of failing lists. */ +    unsigned long skipped;      /* Count of skipped tests (passed). */ +    unsigned long allocated;    /* The size of the results table. */      enum test_status *results;  /* Table of results by test number. */      int aborted;                /* Whether the set as aborted. */      int reported;               /* Whether the results were reported. */ @@ -131,8 +160,9 @@ Failed Set                 Fail/Total (%) Skip Stat  Failing Tests\n\  -------------------------- -------------- ---- ----  ------------------------";  /* Include the file name and line number in malloc failures. */ -#define xmalloc(size)   x_malloc((size), __FILE__, __LINE__) -#define xstrdup(p)      x_strdup((p), __FILE__, __LINE__) +#define xmalloc(size)     x_malloc((size), __FILE__, __LINE__) +#define xrealloc(p, size) x_realloc((p), (size), __FILE__, __LINE__) +#define xstrdup(p)        x_strdup((p), __FILE__, __LINE__)  /* @@ -164,7 +194,7 @@ x_malloc(size_t size, const char *file, int line)      void *p;      p = malloc(size); -    if (!p) +    if (p == NULL)          sysdie("failed to malloc %lu bytes at %s line %d",                 (unsigned long) size, file, line);      return p; @@ -172,6 +202,20 @@ x_malloc(size_t size, const char *file, int line)  /* + * Reallocate memory, reporting a fatal error and exiting on failure. + */ +static void * +x_realloc(void *p, size_t size, const char *file, int line) +{ +    p = realloc(p, size); +    if (p == NULL) +        sysdie("failed to realloc %lu bytes at %s line %d", +               (unsigned long) size, file, line); +    return p; +} + + +/*   * Copy a string, reporting a fatal error and exiting on failure.   */  static char * @@ -182,7 +226,7 @@ x_strdup(const char *s, const char *file, int line)      len = strlen(s) + 1;      p = malloc(len); -    if (!p) +    if (p == NULL)          sysdie("failed to strdup %lu bytes at %s line %d",                 (unsigned long) len, file, line);      memcpy(p, s, len); @@ -235,62 +279,6 @@ skip_whitespace(const char *p)  /* - * Read the first line of test output, which should contain the range of - * test numbers, and initialize the testset structure.  Assume it was zeroed - * before being passed in.  Return true if initialization succeeds, false - * otherwise. - */ -static int -test_init(const char *line, struct testset *ts) -{ -    int i; - -    /* -     * Prefer a simple number of tests, but if the count is given as a range -     * such as 1..10, accept that too for compatibility with Perl's -     * Test::Harness. -     */ -    line = skip_whitespace(line); -    if (strncmp(line, "1..", 3) == 0) -        line += 3; - -    /* -     * Get the count, check it for validity, and initialize the struct.  If we -     * have something of the form "1..0 # skip foo", the whole file was -     * skipped; record that. -     */ -    i = strtol(line, (char **) &line, 10); -    if (i == 0) { -        line = skip_whitespace(line); -        if (*line == '#') { -            line = skip_whitespace(line + 1); -            if (strncasecmp(line, "skip", 4) == 0) { -                line = skip_whitespace(line + 4); -                if (*line != '\0') { -                    ts->reason = xstrdup(line); -                    ts->reason[strlen(ts->reason) - 1] = '\0'; -                } -                ts->all_skipped = 1; -                ts->aborted = 1; -                return 0; -            } -        } -    } -    if (i <= 0) { -        puts("ABORTED (invalid test count)"); -        ts->aborted = 1; -        ts->reported = 1; -        return 0; -    } -    ts->count = i; -    ts->results = xmalloc(ts->count * sizeof(enum test_status)); -    for (i = 0; i < ts->count; i++) -        ts->results[i] = TEST_INVALID; -    return 1; -} - - -/*   * Start a program, connecting its stdout to a pipe on our end and its stderr   * to /dev/null, and storing the file descriptor to read from in the two   * argument.  Returns the PID of the new process.  Errors are fatal. @@ -340,7 +328,7 @@ test_start(const char *path, int *fd)  static void  test_backspace(struct testset *ts)  { -    int i; +    unsigned int i;      if (!isatty(STDOUT_FILENO))          return; @@ -355,6 +343,87 @@ test_backspace(struct testset *ts)  /* + * Read the plan line of test output, which should contain the range of test + * numbers.  We may initialize the testset structure here if we haven't yet + * seen a test.  Return true if initialization succeeded and the test should + * continue, false otherwise. + */ +static int +test_plan(const char *line, struct testset *ts) +{ +    unsigned long i; +    long n; + +    /* +     * Accept a plan without the leading 1.. for compatibility with older +     * versions of runtests.  This will only be allowed if we've not yet seen +     * a test result. +     */ +    line = skip_whitespace(line); +    if (strncmp(line, "1..", 3) == 0) +        line += 3; + +    /* +     * Get the count, check it for validity, and initialize the struct.  If we +     * have something of the form "1..0 # skip foo", the whole file was +     * skipped; record that.  If we do skip the whole file, zero out all of +     * our statistics, since they're no longer relevant. +     */ +    n = strtol(line, (char **) &line, 10); +    if (n == 0) { +        line = skip_whitespace(line); +        if (*line == '#') { +            line = skip_whitespace(line + 1); +            if (strncasecmp(line, "skip", 4) == 0) { +                line = skip_whitespace(line + 4); +                if (*line != '\0') { +                    ts->reason = xstrdup(line); +                    ts->reason[strlen(ts->reason) - 1] = '\0'; +                } +                ts->all_skipped = 1; +                ts->aborted = 1; +                ts->count = 0; +                ts->passed = 0; +                ts->skipped = 0; +                ts->failed = 0; +                return 0; +            } +        } +    } +    if (n <= 0) { +        puts("ABORTED (invalid test count)"); +        ts->aborted = 1; +        ts->reported = 1; +        return 0; +    } +    if (ts->plan == PLAN_INIT && ts->allocated == 0) { +        ts->count = n; +        ts->allocated = n; +        ts->plan = PLAN_FIRST; +        ts->results = xmalloc(ts->count * sizeof(enum test_status)); +        for (i = 0; i < ts->count; i++) +            ts->results[i] = TEST_INVALID; +    } else if (ts->plan == PLAN_PENDING) { +        if ((unsigned long) n < ts->count) { +            printf("ABORTED (invalid test number %lu)\n", ts->count); +            ts->aborted = 1; +            ts->reported = 1; +            return 0; +        } +        ts->count = n; +        if ((unsigned long) n > ts->allocated) { +            ts->results = xrealloc(ts->results, n * sizeof(enum test_status)); +            for (i = ts->allocated; i < ts->count; i++) +                ts->results[i] = TEST_INVALID; +            ts->allocated = n; +        } +        ts->plan = PLAN_FINAL; +    } +    return 1; +} + + +/*   * Given a single line of output from a test, parse it and return the success   * status of that test.  Anything printed to stdout not matching the form   * /^(not )?ok \d+/ is ignored.  Sets ts->current to the test number that just @@ -366,20 +435,21 @@ test_checkline(const char *line, struct testset *ts)      enum test_status status = TEST_PASS;      const char *bail;      char *end; -    int current; +    long number; +    unsigned long i, current;      /* Before anything, check for a test abort. */      bail = strstr(line, "Bail out!");      if (bail != NULL) {          bail = skip_whitespace(bail + strlen("Bail out!"));          if (*bail != '\0') { -            int length; +            size_t length;              length = strlen(bail);              if (bail[length - 1] == '\n')                  length--;              test_backspace(ts); -            printf("ABORTED (%.*s)\n", length, bail); +            printf("ABORTED (%.*s)\n", (int) length, bail);              ts->reported = 1;          }          ts->aborted = 1; @@ -393,6 +463,26 @@ test_checkline(const char *line, struct testset *ts)      if (line[strlen(line) - 1] != '\n')          return; +    /* If the line begins with a hash mark, ignore it. */ +    if (line[0] == '#') +        return; + +    /* If we haven't yet seen a plan, look for one. */ +    if (ts->plan == PLAN_INIT && isdigit((unsigned char)(*line))) { +        if (!test_plan(line, ts)) +            return; +    } else if (strncmp(line, "1..", 3) == 0) { +        if (ts->plan == PLAN_PENDING) { +            if (!test_plan(line, ts)) +                return; +        } else { +            puts("ABORTED (multiple plans)"); +            ts->aborted = 1; +            ts->reported = 1; +            return; +        } +    } +      /* Parse the line, ignoring something we can't parse. */      if (strncmp(line, "not ", 4) == 0) {          status = TEST_FAIL; @@ -402,17 +492,36 @@ test_checkline(const char *line, struct testset *ts)          return;      line = skip_whitespace(line + 2);      errno = 0; -    current = strtol(line, &end, 10); +    number = strtol(line, &end, 10);      if (errno != 0 || end == line) -        current = ts->current + 1; -    if (current <= 0 || current > ts->count) { +        number = ts->current + 1; +    current = number; +    if (number <= 0 || (current > ts->count && ts->plan == PLAN_FIRST)) {          test_backspace(ts); -        printf("ABORTED (invalid test number %d)\n", current); +        printf("ABORTED (invalid test number %lu)\n", current);          ts->aborted = 1;          ts->reported = 1;          return;      } +    /* We have a valid test result.  Tweak the results array if needed. */ +    if (ts->plan == PLAN_INIT || ts->plan == PLAN_PENDING) { +        ts->plan = PLAN_PENDING; +        if (current > ts->count) +            ts->count = current; +        if (current > ts->allocated) { +            unsigned long n; + +            n = (ts->allocated == 0) ? 32 : ts->allocated * 2; +            if (n < current) +                n = current; +            ts->results = xrealloc(ts->results, n * sizeof(enum test_status)); +            for (i = ts->allocated; i < n; i++) +                ts->results[i] = TEST_INVALID; +            ts->allocated = n; +        } +    } +      /*       * Handle directives.  We should probably do something more interesting       * with unexpected passes of todo tests. @@ -431,7 +540,7 @@ test_checkline(const char *line, struct testset *ts)      /* Make sure that the test number is in range and not a duplicate. */      if (ts->results[current - 1] != TEST_INVALID) {          test_backspace(ts); -        printf("ABORTED (duplicate test number %d)\n", current); +        printf("ABORTED (duplicate test number %lu)\n", current);          ts->aborted = 1;          ts->reported = 1;          return; @@ -442,13 +551,13 @@ test_checkline(const char *line, struct testset *ts)          case TEST_PASS: ts->passed++;   break;          case TEST_FAIL: ts->failed++;   break;          case TEST_SKIP: ts->skipped++;  break; -        default:                        break; +        case TEST_INVALID:              break;      }      ts->current = current;      ts->results[current - 1] = status;      test_backspace(ts);      if (isatty(STDOUT_FILENO)) { -        ts->length = printf("%d/%d", current, ts->count); +        ts->length = printf("%lu/%lu", current, ts->count);          fflush(stdout);      }  } @@ -461,12 +570,13 @@ test_checkline(const char *line, struct testset *ts)   * chars plus the space needed would go over the limit (use a limit of 0 to   * disable this.   */ -static int -test_print_range(int first, int last, int chars, int limit) +static unsigned int +test_print_range(unsigned long first, unsigned long last, unsigned int chars, +                 unsigned int limit)  { -    int needed = 0; -    int out = 0; -    int n; +    unsigned int needed = 0; +    unsigned int out = 0; +    unsigned long n;      if (chars > 0) {          needed += 2; @@ -484,8 +594,8 @@ test_print_range(int first, int last, int chars, int limit)              out += printf("...");      } else {          if (last > first) -            out += printf("%d-", first); -        out += printf("%d", last); +            out += printf("%lu-", first); +        out += printf("%lu", last);      }      return out;  } @@ -500,16 +610,16 @@ test_print_range(int first, int last, int chars, int limit)  static void  test_summarize(struct testset *ts, int status)  { -    int i; -    int missing = 0; -    int failed = 0; -    int first = 0; -    int last = 0; +    unsigned long i; +    unsigned long missing = 0; +    unsigned long failed = 0; +    unsigned long first = 0; +    unsigned long last = 0;      if (ts->aborted) {          fputs("ABORTED", stdout);          if (ts->count > 0) -            printf(" (passed %d/%d)", ts->passed, ts->count - ts->skipped); +            printf(" (passed %lu/%lu)", ts->passed, ts->count - ts->skipped);      } else {          for (i = 0; i < ts->count; i++) {              if (ts->results[i] == TEST_INVALID) { @@ -553,9 +663,9 @@ test_summarize(struct testset *ts, int status)              fputs(!status ? "ok" : "dubious", stdout);              if (ts->skipped > 0) {                  if (ts->skipped == 1) -                    printf(" (skipped %d test)", ts->skipped); +                    printf(" (skipped %lu test)", ts->skipped);                  else -                    printf(" (skipped %d tests)", ts->skipped); +                    printf(" (skipped %lu tests)", ts->skipped);              }          }      } @@ -570,8 +680,9 @@ test_summarize(struct testset *ts, int status)  /*   * Given a test set, analyze the results, classify the exit status, handle a - * few special error messages, and then pass it along to test_summarize() - * for the regular output. + * few special error messages, and then pass it along to test_summarize() for + * the regular output.  Returns true if the test set ran successfully and all + * tests passed or were skipped, false otherwise.   */  static int  test_analyze(struct testset *ts) @@ -606,6 +717,10 @@ test_analyze(struct testset *ts)      } else if (WIFSIGNALED(ts->status)) {          test_summarize(ts, -WTERMSIG(ts->status));          return 0; +    } else if (ts->plan != PLAN_FIRST && ts->plan != PLAN_FINAL) { +        puts("ABORTED (no valid test plan)"); +        ts->aborted = 1; +        return 0;      } else {          test_summarize(ts, 0);          return (ts->failed == 0); @@ -622,14 +737,12 @@ static int  test_run(struct testset *ts)  {      pid_t testpid, child; -    int outfd, i, status; +    int outfd, status; +    unsigned long i;      FILE *output;      char buffer[BUFSIZ]; -    /* -     * Initialize the test and our data structures, flagging this set in error -     * if the initialization fails. -     */ +    /* Run the test program. */      testpid = test_start(ts->path, &outfd);      output = fdopen(outfd, "r");      if (!output) { @@ -637,15 +750,11 @@ test_run(struct testset *ts)          fflush(stdout);          sysdie("fdopen failed");      } -    if (!fgets(buffer, sizeof(buffer), output)) -        ts->aborted = 1; -    if (!ts->aborted && !test_init(buffer, ts)) -        ts->aborted = 1;      /* Pass each line of output to test_checkline(). */      while (!ts->aborted && fgets(buffer, sizeof(buffer), output))          test_checkline(buffer, ts); -    if (ferror(output)) +    if (ferror(output) || ts->plan == PLAN_INIT)          ts->aborted = 1;      test_backspace(ts); @@ -686,7 +795,8 @@ static void  test_fail_summary(const struct testlist *fails)  {      struct testset *ts; -    int i, chars, total, first, last; +    unsigned int chars; +    unsigned long i, first, last, total;      puts(header); @@ -695,7 +805,7 @@ test_fail_summary(const struct testlist *fails)      for (; fails; fails = fails->next) {          ts = fails->ts;          total = ts->count - ts->skipped; -        printf("%-26.26s %4d/%-4d %3.0f%% %4d ", ts->file, ts->failed, +        printf("%-26.26s %4lu/%-4lu %3.0f%% %4lu ", ts->file, ts->failed,                 total, total ? (ts->failed * 100.0) / total : 0,                 ts->skipped);          if (WIFEXITED(ts->status)) @@ -711,19 +821,25 @@ test_fail_summary(const struct testlist *fails)          last = 0;          for (i = 0; i < ts->count; i++) {              if (ts->results[i] == TEST_FAIL) { -                if (first && i == last) +                if (first != 0 && i == last)                      last = i + 1;                  else { -                    if (first) +                    if (first != 0)                          chars += test_print_range(first, last, chars, 20);                      first = i + 1;                      last = i + 1;                  }              }          } -        if (first) +        if (first != 0)              test_print_range(first, last, chars, 20);          putchar('\n'); +        free(ts->file); +        free(ts->path); +        free(ts->results); +        if (ts->reason != NULL) +            free(ts->reason); +        free(ts);      }  } @@ -746,7 +862,7 @@ find_test(const char *name, struct testset *ts, const char *source,  {      char *path;      const char *bases[] = { ".", build, source, NULL }; -    int i; +    unsigned int i;      for (i = 0; bases[i] != NULL; i++) {          path = xmalloc(strlen(bases[i]) + strlen(name) + 4); @@ -778,20 +894,21 @@ static int  test_batch(const char *testlist, const char *source, const char *build)  {      FILE *tests; -    size_t length, i; -    size_t longest = 0; +    unsigned int length, i; +    unsigned int longest = 0;      char buffer[BUFSIZ]; -    int line; +    unsigned int line;      struct testset ts, *tmp;      struct timeval start, end;      struct rusage stats; -    struct testlist *failhead = 0; -    struct testlist *failtail = 0; -    int total = 0; -    int passed = 0; -    int skipped = 0; -    int failed = 0; -    int aborted = 0; +    struct testlist *failhead = NULL; +    struct testlist *failtail = NULL; +    struct testlist *next; +    unsigned long total = 0; +    unsigned long passed = 0; +    unsigned long skipped = 0; +    unsigned long failed = 0; +    unsigned long aborted = 0;      /*       * Open our file of tests to run and scan it, checking for lines that @@ -805,7 +922,7 @@ test_batch(const char *testlist, const char *source, const char *build)          line++;          length = strlen(buffer) - 1;          if (buffer[length] != '\n') { -            fprintf(stderr, "%s:%d: line too long\n", testlist, line); +            fprintf(stderr, "%s:%u: line too long\n", testlist, line);              exit(1);          }          if (length > longest) @@ -834,7 +951,7 @@ test_batch(const char *testlist, const char *source, const char *build)          line++;          length = strlen(buffer) - 1;          if (buffer[length] != '\n') { -            fprintf(stderr, "%s:%d: line too long\n", testlist, line); +            fprintf(stderr, "%s:%u: line too long\n", testlist, line);              exit(1);          }          buffer[length] = '\0'; @@ -844,12 +961,14 @@ test_batch(const char *testlist, const char *source, const char *build)          if (isatty(STDOUT_FILENO))              fflush(stdout);          memset(&ts, 0, sizeof(ts)); +        ts.plan = PLAN_INIT;          ts.file = xstrdup(buffer);          find_test(buffer, &ts, source, build);          ts.reason = NULL;          if (test_run(&ts)) {              free(ts.file);              free(ts.path); +            free(ts.results);              if (ts.reason != NULL)                  free(ts.reason);          } else { @@ -858,13 +977,13 @@ test_batch(const char *testlist, const char *source, const char *build)              if (!failhead) {                  failhead = xmalloc(sizeof(struct testset));                  failhead->ts = tmp; -                failhead->next = 0; +                failhead->next = NULL;                  failtail = failhead;              } else {                  failtail->next = xmalloc(sizeof(struct testset));                  failtail = failtail->next;                  failtail->ts = tmp; -                failtail->next = 0; +                failtail->next = NULL;              }          }          aborted += ts.aborted; @@ -880,29 +999,35 @@ test_batch(const char *testlist, const char *source, const char *build)      getrusage(RUSAGE_CHILDREN, &stats);      /* Print out our final results. */ -    if (failhead) +    if (failhead != NULL) {          test_fail_summary(failhead); +        while (failhead != NULL) { +            next = failhead->next; +            free(failhead); +            failhead = next; +        } +    }      putchar('\n');      if (aborted != 0) {          if (aborted == 1) -            printf("Aborted %d test set", aborted); +            printf("Aborted %lu test set", aborted);          else -            printf("Aborted %d test sets", aborted); -        printf(", passed %d/%d tests", passed, total); +            printf("Aborted %lu test sets", aborted); +        printf(", passed %lu/%lu tests", passed, total);      }      else if (failed == 0)          fputs("All tests successful", stdout);      else -        printf("Failed %d/%d tests, %.2f%% okay", failed, total, +        printf("Failed %lu/%lu tests, %.2f%% okay", failed, total,                 (total - failed) * 100.0 / total);      if (skipped != 0) {          if (skipped == 1) -            printf(", %d test skipped", skipped); +            printf(", %lu test skipped", skipped);          else -            printf(", %d tests skipped", skipped); +            printf(", %lu tests skipped", skipped);      }      puts("."); -    printf("Files=%d,  Tests=%d", line, total); +    printf("Files=%u,  Tests=%lu", line, total);      printf(",  %.2f seconds", tv_diff(&end, &start));      printf(" (%.2f usr + %.2f sys = %.2f CPU)\n",             tv_seconds(&stats.ru_utime), tv_seconds(&stats.ru_stime), diff --git a/tests/tap/basic.c b/tests/tap/basic.c index 5ca9ff4..829f91a 100644 --- a/tests/tap/basic.c +++ b/tests/tap/basic.c @@ -2,12 +2,13 @@   * Some utility routines for writing tests.   *   * Herein are a variety of utility routines for writing tests.  All routines - * of the form ok*() take a test number and some number of appropriate + * of the form ok() or is*() take a test number and some number of appropriate   * arguments, check to be sure the results match the expected output using the   * arguments, and print out something appropriate for that test number.  Other - * utility routines help in constructing more complex tests. + * utility routines help in constructing more complex tests, skipping tests, + * or setting up the TAP output format.   * - * Copyright 2009 Russ Allbery <rra@stanford.edu> + * Copyright 2009, 2010 Russ Allbery <rra@stanford.edu>   * Copyright 2006, 2007, 2008   *     Board of Trustees, Leland Stanford Jr. University   * Copyright (c) 2004, 2005, 2006 @@ -34,7 +35,7 @@   * The test count.  Always contains the number that will be used for the next   * test status.   */ -int testnum = 1; +unsigned long testnum = 1;  /*   * Status information stored so that we can give a test summary at the end of @@ -44,10 +45,14 @@ int testnum = 1;   * We also store the PID of the process that called plan() and only summarize   * results when that process exits, so as to not misreport results in forked   * processes. + * + * If _lazy is true, we're doing lazy planning and will print out the plan + * based on the last test number at the end of testing.   */ -static int _planned = 0; -static int _failed  = 0; +static unsigned long _planned = 0; +static unsigned long _failed  = 0;  static pid_t _process = 0; +static int _lazy = 0;  /* @@ -57,22 +62,28 @@ static pid_t _process = 0;  static void  finish(void)  { -    int highest = testnum - 1; - -    if (_process != 0 && getpid() == _process && _planned > 0) { +    unsigned long highest = testnum - 1; + +    if (_planned == 0 && !_lazy) +        return; +    if (_process != 0 && getpid() == _process) { +        if (_lazy) { +            printf("1..%lu\n", highest); +            _planned = highest; +        }          if (_planned > highest) -            printf("# Looks like you planned %d test%s but only ran %d\n", +            printf("# Looks like you planned %lu test%s but only ran %lu\n",                     _planned, (_planned > 1 ? "s" : ""), highest);          else if (_planned < highest) -            printf("# Looks like you planned %d test%s but ran %d extra\n", +            printf("# Looks like you planned %lu test%s but ran %lu extra\n",                     _planned, (_planned > 1 ? "s" : ""), highest - _planned);          else if (_failed > 0) -            printf("# Looks like you failed %d test%s of %d\n", _failed, +            printf("# Looks like you failed %lu test%s of %lu\n", _failed,                     (_failed > 1 ? "s" : ""), _planned);          else if (_planned > 1) -            printf("# All %d tests successful or skipped\n", _planned); +            printf("# All %lu tests successful or skipped\n", _planned);          else -            printf("# %d test successful or skipped\n", _planned); +            printf("# %lu test successful or skipped\n", _planned);      }  } @@ -82,12 +93,12 @@ finish(void)   * the number of tests in the test suite.   */  void -plan(int count) +plan(unsigned long count)  {      if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)          fprintf(stderr, "# cannot set stdout to line buffered: %s\n",                  strerror(errno)); -    printf("1..%d\n", count); +    printf("1..%lu\n", count);      testnum = 1;      _planned = count;      _process = getpid(); @@ -96,6 +107,23 @@ plan(int count)  /* + * Initialize things for lazy planning, where we'll automatically print out a + * plan at the end of the program.  Turns on line buffering on stdout as well. + */ +void +plan_lazy(void) +{ +    if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0) +        fprintf(stderr, "# cannot set stdout to line buffered: %s\n", +                strerror(errno)); +    testnum = 1; +    _process = getpid(); +    _lazy = 1; +    atexit(finish); +} + + +/*   * Skip the entire test suite and exits.  Should be called instead of plan(),   * not after it, since it prints out a special plan line.   */ @@ -134,7 +162,7 @@ print_desc(const char *format, va_list args)  void  ok(int success, const char *format, ...)  { -    printf("%sok %d", success ? "" : "not ", testnum++); +    printf("%sok %lu", success ? "" : "not ", testnum++);      if (!success)          _failed++;      if (format != NULL) { @@ -149,12 +177,27 @@ ok(int success, const char *format, ...)  /* + * Same as ok(), but takes the format arguments as a va_list. + */ +void +okv(int success, const char *format, va_list args) +{ +    printf("%sok %lu", success ? "" : "not ", testnum++); +    if (!success) +        _failed++; +    if (format != NULL) +        print_desc(format, args); +    putchar('\n'); +} + + +/*   * Skip a test.   */  void  skip(const char *reason, ...)  { -    printf("ok %d # skip", testnum++); +    printf("ok %lu # skip", testnum++);      if (reason != NULL) {          va_list args; @@ -171,12 +214,12 @@ skip(const char *reason, ...)   * Report the same status on the next count tests.   */  void -ok_block(int count, int status, const char *format, ...) +ok_block(unsigned long count, int status, const char *format, ...)  { -    int i; +    unsigned long i;      for (i = 0; i < count; i++) { -        printf("%sok %d", status ? "" : "not ", testnum++); +        printf("%sok %lu", status ? "" : "not ", testnum++);          if (!status)              _failed++;          if (format != NULL) { @@ -195,12 +238,12 @@ ok_block(int count, int status, const char *format, ...)   * Skip the next count tests.   */  void -skip_block(int count, const char *reason, ...) +skip_block(unsigned long count, const char *reason, ...)  { -    int i; +    unsigned long i;      for (i = 0; i < count; i++) { -        printf("ok %d # skip", testnum++); +        printf("ok %lu # skip", testnum++);          if (reason != NULL) {              va_list args; @@ -219,13 +262,13 @@ skip_block(int count, const char *reason, ...)   * if those two numbers match.   */  void -is_int(int wanted, int seen, const char *format, ...) +is_int(long wanted, long seen, const char *format, ...)  {      if (wanted == seen) -        printf("ok %d", testnum++); +        printf("ok %lu", testnum++);      else { -        printf("# wanted: %d\n#   seen: %d\n", wanted, seen); -        printf("not ok %d", testnum++); +        printf("# wanted: %ld\n#   seen: %ld\n", wanted, seen); +        printf("not ok %lu", testnum++);          _failed++;      }      if (format != NULL) { @@ -251,10 +294,10 @@ is_string(const char *wanted, const char *seen, const char *format, ...)      if (seen == NULL)          seen = "(null)";      if (strcmp(wanted, seen) == 0) -        printf("ok %d", testnum++); +        printf("ok %lu", testnum++);      else {          printf("# wanted: %s\n#   seen: %s\n", wanted, seen); -        printf("not ok %d", testnum++); +        printf("not ok %lu", testnum++);          _failed++;      }      if (format != NULL) { @@ -276,10 +319,10 @@ void  is_double(double wanted, double seen, const char *format, ...)  {      if (wanted == seen) -        printf("ok %d", testnum++); +        printf("ok %lu", testnum++);      else {          printf("# wanted: %g\n#   seen: %g\n", wanted, seen); -        printf("not ok %d", testnum++); +        printf("not ok %lu", testnum++);          _failed++;      }      if (format != NULL) { @@ -301,11 +344,11 @@ void  is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)  {      if (wanted == seen) -        printf("ok %d", testnum++); +        printf("ok %lu", testnum++);      else {          printf("# wanted: %lx\n#   seen: %lx\n", (unsigned long) wanted,                 (unsigned long) seen); -        printf("not ok %d", testnum++); +        printf("not ok %lu", testnum++);          _failed++;      }      if (format != NULL) { @@ -354,3 +397,88 @@ sysbail(const char *format, ...)      printf(": %s\n", strerror(oerrno));      exit(1);  } + + +/* + * Report a diagnostic to stderr. + */ +void +diag(const char *format, ...) +{ +    va_list args; + +    fflush(stdout); +    printf("# "); +    va_start(args, format); +    vprintf(format, args); +    va_end(args); +    printf("\n"); +} + + +/* + * Report a diagnostic to stderr, appending strerror(errno). + */ +void +sysdiag(const char *format, ...) +{ +    va_list args; +    int oerrno = errno; + +    fflush(stdout); +    printf("# "); +    va_start(args, format); +    vprintf(format, args); +    va_end(args); +    printf(": %s\n", strerror(oerrno)); +} + + +/* + * Locate a test file.  Given the partial path to a file, look under BUILD and + * then SOURCE for the file and return the full path to the file.  Returns + * NULL if the file doesn't exist.  A non-NULL return should be freed with + * test_file_path_free(). + * + * This function uses sprintf because it attempts to be independent of all + * other portability layers.  The use immediately after a memory allocation + * should be safe without using snprintf or strlcpy/strlcat. + */ +char * +test_file_path(const char *file) +{ +    char *base; +    char *path = NULL; +    size_t length; +    const char *envs[] = { "BUILD", "SOURCE", NULL }; +    int i; + +    for (i = 0; envs[i] != NULL; i++) { +        base = getenv(envs[i]); +        if (base == NULL) +            continue; +        length = strlen(base) + 1 + strlen(file) + 1; +        path = malloc(length); +        if (path == NULL) +            sysbail("cannot allocate memory"); +        sprintf(path, "%s/%s", base, file); +        if (access(path, R_OK) == 0) +            break; +        free(path); +        path = NULL; +    } +    return path; +} + + +/* + * Free a path returned from test_file_path().  This function exists primarily + * for Windows, where memory must be freed from the same library domain that + * it was allocated from. + */ +void +test_file_path_free(char *path) +{ +    if (path != NULL) +        free(path); +} diff --git a/tests/tap/basic.h b/tests/tap/basic.h index efe94ba..9602db4 100644 --- a/tests/tap/basic.h +++ b/tests/tap/basic.h @@ -1,6 +1,7 @@  /*   * Basic utility routines for the TAP protocol.   * + * Copyright 2009, 2010 Russ Allbery <rra@stanford.edu>   * Copyright 2006, 2007, 2008   *     Board of Trustees, Leland Stanford Jr. University   * Copyright (c) 2004, 2005, 2006 @@ -14,6 +15,7 @@  #ifndef TAP_BASIC_H  #define TAP_BASIC_H 1 +#include <stdarg.h>             /* va_list */  #include <sys/types.h>          /* pid_t */  /* @@ -56,29 +58,40 @@ BEGIN_DECLS   * The test count.  Always contains the number that will be used for the next   * test status.   */ -extern int testnum; +extern unsigned long testnum;  /* Print out the number of tests and set standard output to line buffered. */ -void plan(int count); +void plan(unsigned long count); + +/* + * Prepare for lazy planning, in which the plan will be  printed automatically + * at the end of the test program. + */ +void plan_lazy(void);  /* Skip the entire test suite.  Call instead of plan. */  void skip_all(const char *format, ...)      __attribute__((__noreturn__, __format__(printf, 1, 2))); -/* Basic reporting functions. */ +/* + * Basic reporting functions.  The okv() function is the same as ok() but + * takes the test description as a va_list to make it easier to reuse the + * reporting infrastructure when writing new tests. + */  void ok(int success, const char *format, ...)      __attribute__((__format__(printf, 2, 3))); +void okv(int success, const char *format, va_list args);  void skip(const char *reason, ...)      __attribute__((__format__(printf, 1, 2)));  /* Report the same status on, or skip, the next count tests. */ -void ok_block(int count, int success, const char *format, ...) +void ok_block(unsigned long count, int success, const char *format, ...)      __attribute__((__format__(printf, 3, 4))); -void skip_block(int count, const char *reason, ...) +void skip_block(unsigned long count, const char *reason, ...)      __attribute__((__format__(printf, 2, 3)));  /* Check an expected value against a seen value. */ -void is_int(int wanted, int seen, const char *format, ...) +void is_int(long wanted, long seen, const char *format, ...)      __attribute__((__format__(printf, 3, 4)));  void is_double(double wanted, double seen, const char *format, ...)      __attribute__((__format__(printf, 3, 4))); @@ -93,6 +106,20 @@ void bail(const char *format, ...)  void sysbail(const char *format, ...)      __attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2))); +/* Report a diagnostic to stderr prefixed with #. */ +void diag(const char *format, ...) +    __attribute__((__nonnull__, __format__(printf, 1, 2))); +void sysdiag(const char *format, ...) +    __attribute__((__nonnull__, __format__(printf, 1, 2))); + +/* + * Find a test file under BUILD or SOURCE, returning the full path.  The + * returned path should be freed with test_file_path_free(). + */ +char *test_file_path(const char *file) +    __attribute__((__malloc__, __nonnull__)); +void test_file_path_free(char *path); +  END_DECLS -#endif /* LIBTEST_H */ +#endif /* TAP_BASIC_H */ diff --git a/tests/tap/kerberos.c b/tests/tap/kerberos.c index 700212e..a17d980 100644 --- a/tests/tap/kerberos.c +++ b/tests/tap/kerberos.c @@ -23,33 +23,6 @@  /* - * Given the partial path to a file, look under BUILD and then SOURCE for the - * file and return the full path to the file in newly-allocated memory. - * Returns NULL if the file doesn't exist. - */ -static char * -find_file(const char *file) -{ -    char *base; -    char *path = NULL; -    const char *envs[] = { "BUILD", "SOURCE", NULL }; -    int i; - -    for (i = 0; envs[i] != NULL; i++) { -        base = getenv(envs[i]); -        if (base == NULL) -            continue; -        path = concatpath(base, file); -        if (access(path, R_OK) == 0) -            break; -        free(path); -        path = NULL; -    } -    return path; -} - - -/*   * Obtain Kerberos tickets for the principal specified in test.principal using   * the keytab specified in test.keytab, both of which are presumed to be in   * tests/data in either the build or the source tree. @@ -78,7 +51,7 @@ kerberos_setup(void)      krb5_creds creds;      /* Read the principal name and find the keytab file. */ -    path = find_file("data/test.principal"); +    path = test_file_path("data/test.principal");      if (path == NULL)          return NULL;      file = fopen(path, "r"); @@ -95,7 +68,7 @@ kerberos_setup(void)          bail("no newline in %s", path);      free(path);      principal[strlen(principal) - 1] = '\0'; -    path = find_file("data/test.keytab"); +    path = test_file_path("data/test.keytab");      if (path == NULL)          return NULL; diff --git a/tests/tap/kerberos.sh b/tests/tap/kerberos.sh index fbeaaba..904cae5 100644 --- a/tests/tap/kerberos.sh +++ b/tests/tap/kerberos.sh @@ -1,4 +1,4 @@ -# Shell function library for Kerberos test support. +# Shell function library to initialize Kerberos credentials  #  # Written by Russ Allbery <rra@stanford.edu>  # Copyright 2009, 2010 Board of Trustees, Leland Stanford Jr. University @@ -10,18 +10,9 @@  # configured.  Sets the global principal variable to the principal to use.  kerberos_setup () {      local keytab -    keytab='' -    for f in "$BUILD/data/test.keytab" "$SOURCE/data/test.keytab" ; do -        if [ -r "$f" ] ; then -            keytab="$f" -        fi -    done -    principal='' -    for f in "$BUILD/data/test.principal" "$SOURCE/data/test.principal" ; do -        if [ -r "$f" ] ; then -            principal=`cat "$BUILD/data/test.principal"` -        fi -    done +    keytab=`test_file_path data/test.keytab` +    principal=`test_file_path data/test.principal` +    principal=`cat "$principal" 2>/dev/null`      if [ -z "$keytab" ] || [ -z "$principal" ] ; then          return 1      fi diff --git a/tests/tap/libtap.sh b/tests/tap/libtap.sh index 1846840..a9b46d4 100644 --- a/tests/tap/libtap.sh +++ b/tests/tap/libtap.sh @@ -1,7 +1,7 @@  # Shell function library for test cases.  #  # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2009 Russ Allbery <rra@stanford.edu> +# Copyright 2009, 2010 Russ Allbery <rra@stanford.edu>  # Copyright 2006, 2007, 2008 Board of Trustees, Leland Stanford Jr. University  #  # See LICENSE for licensing terms. @@ -15,10 +15,22 @@ plan () {      trap finish 0  } +# Prepare for lazy planning. +plan_lazy () { +    count=1 +    planned=0 +    failed=0 +    trap finish 0 +} +  # Report the test status on exit.  finish () {      local highest looks      highest=`expr "$count" - 1` +    if [ "$planned" = 0 ] ; then +        echo "1..$highest" +        planned="$highest" +    fi      looks='# Looks like you'      if [ "$planned" -gt 0 ] ; then          if [ "$planned" -gt "$highest" ] ; then @@ -146,3 +158,21 @@ bail () {      echo 'Bail out!' "$@"      exit 1  } + +# Output a diagnostic on standard error, preceded by the required # mark. +diag () { +    echo '#' "$@" +} + +# Search for the given file first in $BUILD and then in $SOURCE and echo the +# path where the file was found, or the empty string if the file wasn't +# found. +test_file_path () { +    if [ -f "$BUILD/$1" ] ; then +        echo "$BUILD/$1" +    elif [ -f "$SOURCE/$1" ] ; then +        echo "$SOURCE/$1" +    else +        echo '' +    fi +} diff --git a/tests/tap/remctl.sh b/tests/tap/remctl.sh index b9667ef..9e01bcf 100644 --- a/tests/tap/remctl.sh +++ b/tests/tap/remctl.sh @@ -10,18 +10,12 @@  remctld_start () {      local keytab principal      rm -f "$BUILD/data/remctld.pid" -    keytab='' -    for f in "$BUILD/data/test.keytab" "$SOURCE/data/test.keytab" ; do -        if [ -r "$f" ] ; then -            keytab="$f" -        fi -    done -    principal='' -    for f in "$BUILD/data/test.principal" "$SOURCE/data/test.principal" ; do -        if [ -r "$f" ] ; then -            principal=`cat "$BUILD/data/test.principal"` -        fi -    done +    keytab=`test_file_path data/test.keytab` +    principal=`test_file_path data/test.principal` +    principal=`cat "$principal" 2>/dev/null` +    if [ -z "$keytab" ] || [ -z "$principal" ] ; then +        return 1 +    fi      if [ -n "$VALGRIND" ] ; then          ( "$VALGRIND" --log-file=valgrind.%p --leak-check=full "$1" -m \            -p 14373 -s "$principal" -P "$BUILD/data/remctld.pid" -f "$2" -d \ diff --git a/tests/util/messages-t.c b/tests/util/messages-t.c index fb82a42..a58f82c 100644 --- a/tests/util/messages-t.c +++ b/tests/util/messages-t.c @@ -146,8 +146,8 @@ test_strerror(int status, const char *output, int error,      char *full_output, *name;      full_output = concat(output, ": ", strerror(error), "\n", (char *) NULL); -    xasprintf(&name, "strerror %d", testnum / 3 + 1); -    is_function_output(function, status, full_output, name); +    xasprintf(&name, "strerror %lu", testnum / 3 + 1); +    is_function_output(function, status, full_output, "%s", name);      free(full_output);      free(name);  } diff --git a/tests/util/xmalloc.c b/tests/util/xmalloc.c index 3bd5588..b6f4564 100644 --- a/tests/util/xmalloc.c +++ b/tests/util/xmalloc.c @@ -246,8 +246,6 @@ main(int argc, char *argv[])      size_t limit = 0;      int willfail = 0;      unsigned char code; -    struct rlimit rl; -    void *tmp;      if (argc < 3)          die("Usage error.  Type, size, and limit must be given."); @@ -290,6 +288,9 @@ main(int argc, char *argv[])       */      if (limit > 0) {  #if HAVE_SETRLIMIT && defined(RLIMIT_AS) +        struct rlimit rl; +        void *tmp; +          rl.rlim_cur = limit;          rl.rlim_max = limit;          if (setrlimit(RLIMIT_AS, &rl) < 0) { diff --git a/util/macros.h b/util/macros.h index 97b2c2b..0104d9f 100644 --- a/util/macros.h +++ b/util/macros.h @@ -8,7 +8,6 @@  #ifndef UTIL_MACROS_H  #define UTIL_MACROS_H 1 -#include <config.h>  #include <portable/macros.h>  /* Used for unused parameters to silence gcc warnings. */ diff --git a/util/messages.c b/util/messages.c index ef920b2..3592692 100644 --- a/util/messages.c +++ b/util/messages.c @@ -107,9 +107,9 @@ const char *message_program_name = NULL;   * handler list, the count of handlers, and the argument list.   */  static void -message_handlers(message_handler_func **list, int count, va_list args) +message_handlers(message_handler_func **list, unsigned int count, va_list args)  { -    int i; +    unsigned int i;      if (*list != stdout_handlers && *list != stderr_handlers)          free(*list); @@ -127,7 +127,7 @@ message_handlers(message_handler_func **list, int count, va_list args)   */  #define HANDLER_FUNCTION(type)                                  \      void                                                        \ -    message_handlers_ ## type(int count, ...)                   \ +    message_handlers_ ## type(unsigned int count, ...)          \      {                                                           \          va_list args;                                           \                                                                  \ @@ -145,7 +145,7 @@ HANDLER_FUNCTION(die)   * Print a message to stdout, supporting message_program_name.   */  void -message_log_stdout(int len UNUSED, const char *fmt, va_list args, int err) +message_log_stdout(size_t len UNUSED, const char *fmt, va_list args, int err)  {      if (message_program_name != NULL)          fprintf(stdout, "%s: ", message_program_name); @@ -162,7 +162,7 @@ message_log_stdout(int len UNUSED, const char *fmt, va_list args, int err)   * stdout so that errors and regular output occur in the right order.   */  void -message_log_stderr(int len UNUSED, const char *fmt, va_list args, int err) +message_log_stderr(size_t len UNUSED, const char *fmt, va_list args, int err)  {      fflush(stdout);      if (message_program_name != NULL) @@ -183,7 +183,7 @@ message_log_stderr(int len UNUSED, const char *fmt, va_list args, int err)   * log the errno information.   */  static void -message_log_syslog(int pri, int len, const char *fmt, va_list args, int err) +message_log_syslog(int pri, size_t len, const char *fmt, va_list args, int err)  {      char *buffer; @@ -218,11 +218,11 @@ message_log_syslog(int pri, int len, const char *fmt, va_list args, int err)   * Do the same sort of wrapper to generate all of the separate syslog logging   * functions.   */ -#define SYSLOG_FUNCTION(name, type)                                     \ -    void                                                                \ -    message_log_syslog_ ## name(int l, const char *f, va_list a, int e) \ -    {                                                                   \ -        message_log_syslog(LOG_ ## type, l, f, a, e);                   \ +#define SYSLOG_FUNCTION(name, type)                                        \ +    void                                                                   \ +    message_log_syslog_ ## name(size_t l, const char *f, va_list a, int e) \ +    {                                                                      \ +        message_log_syslog(LOG_ ## type, l, f, a, e);                      \      }  SYSLOG_FUNCTION(debug,   DEBUG)  SYSLOG_FUNCTION(info,    INFO) @@ -243,7 +243,7 @@ debug(const char *format, ...)  {      va_list args;      message_handler_func *log; -    int length; +    ssize_t length;      if (debug_handlers == NULL)          return; @@ -254,7 +254,7 @@ debug(const char *format, ...)          return;      for (log = debug_handlers; *log != NULL; log++) {          va_start(args, format); -        (**log)(length, format, args, 0); +        (**log)((size_t) length, format, args, 0);          va_end(args);      }  } @@ -264,7 +264,7 @@ notice(const char *format, ...)  {      va_list args;      message_handler_func *log; -    int length; +    ssize_t length;      va_start(args, format);      length = vsnprintf(NULL, 0, format, args); @@ -273,7 +273,7 @@ notice(const char *format, ...)          return;      for (log = notice_handlers; *log != NULL; log++) {          va_start(args, format); -        (**log)(length, format, args, 0); +        (**log)((size_t) length, format, args, 0);          va_end(args);      }  } @@ -283,7 +283,7 @@ sysnotice(const char *format, ...)  {      va_list args;      message_handler_func *log; -    int length; +    ssize_t length;      int error = errno;      va_start(args, format); @@ -293,7 +293,7 @@ sysnotice(const char *format, ...)          return;      for (log = notice_handlers; *log != NULL; log++) {          va_start(args, format); -        (**log)(length, format, args, error); +        (**log)((size_t) length, format, args, error);          va_end(args);      }  } @@ -303,7 +303,7 @@ warn(const char *format, ...)  {      va_list args;      message_handler_func *log; -    int length; +    ssize_t length;      va_start(args, format);      length = vsnprintf(NULL, 0, format, args); @@ -312,7 +312,7 @@ warn(const char *format, ...)          return;      for (log = warn_handlers; *log != NULL; log++) {          va_start(args, format); -        (**log)(length, format, args, 0); +        (**log)((size_t) length, format, args, 0);          va_end(args);      }  } @@ -322,7 +322,7 @@ syswarn(const char *format, ...)  {      va_list args;      message_handler_func *log; -    int length; +    ssize_t length;      int error = errno;      va_start(args, format); @@ -332,7 +332,7 @@ syswarn(const char *format, ...)          return;      for (log = warn_handlers; *log != NULL; log++) {          va_start(args, format); -        (**log)(length, format, args, error); +        (**log)((size_t) length, format, args, error);          va_end(args);      }  } @@ -342,7 +342,7 @@ die(const char *format, ...)  {      va_list args;      message_handler_func *log; -    int length; +    ssize_t length;      va_start(args, format);      length = vsnprintf(NULL, 0, format, args); @@ -350,7 +350,7 @@ die(const char *format, ...)      if (length >= 0)          for (log = die_handlers; *log != NULL; log++) {              va_start(args, format); -            (**log)(length, format, args, 0); +            (**log)((size_t) length, format, args, 0);              va_end(args);          }      exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1); @@ -361,7 +361,7 @@ sysdie(const char *format, ...)  {      va_list args;      message_handler_func *log; -    int length; +    ssize_t length;      int error = errno;      va_start(args, format); @@ -370,7 +370,7 @@ sysdie(const char *format, ...)      if (length >= 0)          for (log = die_handlers; *log != NULL; log++) {              va_start(args, format); -            (**log)(length, format, args, error); +            (**log)((size_t) length, format, args, error);              va_end(args);          }      exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1); diff --git a/util/messages.h b/util/messages.h index ff86f39..dbdb256 100644 --- a/util/messages.h +++ b/util/messages.h @@ -49,35 +49,35 @@ void sysdie(const char *, ...)   * of those handlers.  These functions are not thread-safe; they set global   * variables.   */ -void message_handlers_debug(int count, ...); -void message_handlers_notice(int count, ...); -void message_handlers_warn(int count, ...); -void message_handlers_die(int count, ...); +void message_handlers_debug(unsigned int count, ...); +void message_handlers_notice(unsigned int count, ...); +void message_handlers_warn(unsigned int count, ...); +void message_handlers_die(unsigned int count, ...);  /*   * Some useful handlers, intended to be passed to message_handlers_*.  All   * handlers take the length of the formatted message, the format, a variadic   * argument list, and the errno setting if any.   */ -void message_log_stdout(int, const char *, va_list, int) +void message_log_stdout(size_t, const char *, va_list, int)      __attribute((__nonnull__)); -void message_log_stderr(int, const char *, va_list, int) +void message_log_stderr(size_t, const char *, va_list, int)      __attribute((__nonnull__)); -void message_log_syslog_debug(int, const char *, va_list, int) +void message_log_syslog_debug(size_t, const char *, va_list, int)      __attribute((__nonnull__)); -void message_log_syslog_info(int, const char *, va_list, int) +void message_log_syslog_info(size_t, const char *, va_list, int)      __attribute((__nonnull__)); -void message_log_syslog_notice(int, const char *, va_list, int) +void message_log_syslog_notice(size_t, const char *, va_list, int)      __attribute((__nonnull__)); -void message_log_syslog_warning(int, const char *, va_list, int) +void message_log_syslog_warning(size_t, const char *, va_list, int)      __attribute((__nonnull__)); -void message_log_syslog_err(int, const char *, va_list, int) +void message_log_syslog_err(size_t, const char *, va_list, int)      __attribute((__nonnull__)); -void message_log_syslog_crit(int, const char *, va_list, int) +void message_log_syslog_crit(size_t, const char *, va_list, int)      __attribute((__nonnull__));  /* The type of a message handler. */ -typedef void (*message_handler_func)(int, const char *, va_list, int); +typedef void (*message_handler_func)(size_t, const char *, va_list, int);  /* If non-NULL, called before exit and its return value passed to exit. */  extern int (*message_fatal_cleanup)(void); | 
