rx: add and export a public keepalive toggle
[openafs.git] / tests / tap / basic.c
index 2cdafa6..8027a31 100644 (file)
@@ -1,24 +1,47 @@
 /*
  * 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
- * 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.
+ * Here are a variety of utility routines for writing tests compatible with
+ * the TAP protocol.  All routines 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, skipping tests, or setting up the TAP
+ * output format.
+ *
+ * This file is part of C TAP Harness.  The current version plus supporting
+ * documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.
  *
  * Copyright 2009, 2010 Russ Allbery <rra@stanford.edu>
- * Copyright 2006, 2007, 2008
- *     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,
- *     2002, 2003 by The Internet Software Consortium and Rich Salz
+ * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008
+ *     The Board of Trustees of the Leland Stanford Junior University
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
  *
- * See LICENSE for licensing terms.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
  */
 
+/* Required for isnan() and isinf(). */
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+
 #include <errno.h>
+#include <math.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -65,6 +88,7 @@ finish(void)
 
     if (_planned == 0 && !_lazy)
         return;
+    fflush(stderr);
     if (_process != 0 && getpid() == _process) {
         if (_lazy) {
             printf("1..%lu\n", highest);
@@ -97,6 +121,7 @@ plan(unsigned long count)
     if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)
         fprintf(stderr, "# cannot set stdout to line buffered: %s\n",
                 strerror(errno));
+    fflush(stderr);
     printf("1..%lu\n", count);
     testnum = 1;
     _planned = count;
@@ -129,6 +154,7 @@ plan_lazy(void)
 void
 skip_all(const char *format, ...)
 {
+    fflush(stderr);
     printf("1..0 # skip");
     if (format != NULL) {
         va_list args;
@@ -161,6 +187,7 @@ print_desc(const char *format, va_list args)
 void
 ok(int success, const char *format, ...)
 {
+    fflush(stderr);
     printf("%sok %lu", success ? "" : "not ", testnum++);
     if (!success)
         _failed++;
@@ -176,11 +203,28 @@ 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)
+{
+    fflush(stderr);
+    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, ...)
 {
+    fflush(stderr);
     printf("ok %lu # skip", testnum++);
     if (reason != NULL) {
         va_list args;
@@ -202,6 +246,7 @@ ok_block(unsigned long count, int status, const char *format, ...)
 {
     unsigned long i;
 
+    fflush(stderr);
     for (i = 0; i < count; i++) {
         printf("%sok %lu", status ? "" : "not ", testnum++);
         if (!status)
@@ -226,6 +271,7 @@ skip_block(unsigned long count, const char *reason, ...)
 {
     unsigned long i;
 
+    fflush(stderr);
     for (i = 0; i < count; i++) {
         printf("ok %lu # skip", testnum++);
         if (reason != NULL) {
@@ -248,6 +294,7 @@ skip_block(unsigned long count, const char *reason, ...)
 void
 is_int(long wanted, long seen, const char *format, ...)
 {
+    fflush(stderr);
     if (wanted == seen)
         printf("ok %lu", testnum++);
     else {
@@ -277,6 +324,7 @@ is_string(const char *wanted, const char *seen, const char *format, ...)
         wanted = "(null)";
     if (seen == NULL)
         seen = "(null)";
+    fflush(stderr);
     if (strcmp(wanted, seen) == 0)
         printf("ok %lu", testnum++);
     else {
@@ -297,12 +345,15 @@ is_string(const char *wanted, const char *seen, const char *format, ...)
 
 /*
  * Takes an expected double and a seen double and assumes the test passes if
- * those two numbers match.
+ * those two numbers are within delta of each other.
  */
 void
-is_double(double wanted, double seen, const char *format, ...)
+is_double(double wanted, double seen, double epsilon, const char *format, ...)
 {
-    if (wanted == seen)
+    fflush(stderr);
+    if ((isnan(wanted) && isnan(seen))
+        || (isinf(wanted) && isinf(seen) && wanted == seen)
+        || fabs(wanted - seen) <= epsilon)
         printf("ok %lu", testnum++);
     else {
         printf("# wanted: %g\n#   seen: %g\n", wanted, seen);
@@ -327,6 +378,7 @@ is_double(double wanted, double seen, const char *format, ...)
 void
 is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)
 {
+    fflush(stderr);
     if (wanted == seen)
         printf("ok %lu", testnum++);
     else {
@@ -354,6 +406,7 @@ bail(const char *format, ...)
 {
     va_list args;
 
+    fflush(stderr);
     fflush(stdout);
     printf("Bail out! ");
     va_start(args, format);
@@ -373,6 +426,7 @@ sysbail(const char *format, ...)
     va_list args;
     int oerrno = errno;
 
+    fflush(stderr);
     fflush(stdout);
     printf("Bail out! ");
     va_start(args, format);
@@ -391,6 +445,7 @@ diag(const char *format, ...)
 {
     va_list args;
 
+    fflush(stderr);
     fflush(stdout);
     printf("# ");
     va_start(args, format);
@@ -409,6 +464,7 @@ sysdiag(const char *format, ...)
     va_list args;
     int oerrno = errno;
 
+    fflush(stderr);
     fflush(stdout);
     printf("# ");
     va_start(args, format);
@@ -416,3 +472,53 @@ sysdiag(const char *format, ...)
     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);
+}