check: Import version 0.9.14
authorSebastian Rasmussen <sebras@hotmail.com>
Sat, 15 Nov 2014 11:53:32 +0000 (12:53 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Sat, 6 Dec 2014 16:48:16 +0000 (17:48 +0100)
This lifts the files almost verbatim (the changes being running though
gst-indent and fixing the FSF address) from the upstream respository.
Therefore this commit reverts some GStreamer-specific patches to check
that will be reintroduced next.

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=727826

27 files changed:
libs/gst/check/libcheck/alarm.c [new file with mode: 0644]
libs/gst/check/libcheck/check.c
libs/gst/check/libcheck/check.h.in
libs/gst/check/libcheck/check_error.c
libs/gst/check/libcheck/check_error.h
libs/gst/check/libcheck/check_impl.h
libs/gst/check/libcheck/check_list.c
libs/gst/check/libcheck/check_list.h
libs/gst/check/libcheck/check_log.c
libs/gst/check/libcheck/check_log.h
libs/gst/check/libcheck/check_msg.c
libs/gst/check/libcheck/check_msg.h
libs/gst/check/libcheck/check_pack.c
libs/gst/check/libcheck/check_pack.h
libs/gst/check/libcheck/check_print.c
libs/gst/check/libcheck/check_print.h
libs/gst/check/libcheck/check_run.c
libs/gst/check/libcheck/check_str.c
libs/gst/check/libcheck/check_str.h
libs/gst/check/libcheck/clock_gettime.c [new file with mode: 0644]
libs/gst/check/libcheck/libcompat.c [new file with mode: 0644]
libs/gst/check/libcheck/libcompat.h [new file with mode: 0644]
libs/gst/check/libcheck/localtime_r.c [new file with mode: 0644]
libs/gst/check/libcheck/strsignal.c [new file with mode: 0644]
libs/gst/check/libcheck/timer_create.c [new file with mode: 0644]
libs/gst/check/libcheck/timer_delete.c [new file with mode: 0644]
libs/gst/check/libcheck/timer_settime.c [new file with mode: 0644]

diff --git a/libs/gst/check/libcheck/alarm.c b/libs/gst/check/libcheck/alarm.c
new file mode 100644 (file)
index 0000000..9f87019
--- /dev/null
@@ -0,0 +1,8 @@
+#include "libcompat.h"
+
+unsigned int
+alarm (unsigned int seconds CK_ATTRIBUTE_UNUSED)
+{
+  assert (0);
+  return 0;
+}
index 2b7f481..af2f45a 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
-#include "config.h"
+#include "../lib/libcompat.h"
 
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <math.h>
 
 #include "check.h"
 #include "check_error.h"
 #include "check_impl.h"
 #include "check_msg.h"
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>             /* for _POSIX_VERSION */
-#endif
-
 #ifndef DEFAULT_TIMEOUT
 #define DEFAULT_TIMEOUT 4
 #endif
 
+/*
+ * When a process exits either normally, with exit(), or
+ * by an uncaught signal, The lower 0x377 bits are passed
+ * to the parent. Of those, only the lower 8 bits are
+ * returned by the WEXITSTATUS() macro.
+ */
+#define WEXITSTATUS_MASK 0xFF
+
 int check_major_version = CHECK_MAJOR_VERSION;
 int check_minor_version = CHECK_MINOR_VERSION;
 int check_micro_version = CHECK_MICRO_VERSION;
@@ -55,7 +60,8 @@ Suite *
 suite_create (const char *name)
 {
   Suite *s;
-  s = emalloc (sizeof (Suite)); /* freed in suite_free */
+
+  s = (Suite *) emalloc (sizeof (Suite));       /* freed in suite_free */
   if (name == NULL)
     s->name = "";
   else
@@ -64,17 +70,37 @@ suite_create (const char *name)
   return s;
 }
 
+int
+suite_tcase (Suite * s, const char *tcname)
+{
+  List *l;
+  TCase *tc;
+
+  if (s == NULL)
+    return 0;
+
+  l = s->tclst;
+  for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
+    tc = (TCase *) check_list_val (l);
+    if (strcmp (tcname, tc->name) == 0)
+      return 1;
+  }
+
+  return 0;
+}
+
 static void
 suite_free (Suite * s)
 {
   List *l;
+
   if (s == NULL)
     return;
   l = s->tclst;
-  for (list_front (l); !list_at_end (l); list_advance (l)) {
-    tcase_free (list_val (l));
+  for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
+    tcase_free ((TCase *) check_list_val (l));
   }
-  list_free (s->tclst);
+  check_list_free (s->tclst);
   free (s);
 }
 
@@ -82,8 +108,10 @@ TCase *
 tcase_create (const char *name)
 {
   char *env;
-  int timeout = DEFAULT_TIMEOUT;
-  TCase *tc = emalloc (sizeof (TCase)); /*freed in tcase_free */
+  double timeout_sec = DEFAULT_TIMEOUT;
+
+  TCase *tc = (TCase *) emalloc (sizeof (TCase));       /*freed in tcase_free */
+
   if (name == NULL)
     tc->name = "";
   else
@@ -91,21 +119,28 @@ tcase_create (const char *name)
 
   env = getenv ("CK_DEFAULT_TIMEOUT");
   if (env != NULL) {
-    int tmp = atoi (env);
-    if (tmp >= 0) {
-      timeout = tmp;
+    char *endptr = NULL;
+    double tmp = strtod (env, &endptr);
+
+    if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
+      timeout_sec = tmp;
     }
   }
 
   env = getenv ("CK_TIMEOUT_MULTIPLIER");
   if (env != NULL) {
-    int tmp = atoi (env);
-    if (tmp >= 0) {
-      timeout = timeout * tmp;
+    char *endptr = NULL;
+    double tmp = strtod (env, &endptr);
+
+    if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
+      timeout_sec = timeout_sec * tmp;
     }
   }
 
-  tc->timeout = timeout;
+  tc->timeout.tv_sec = (time_t) floor (timeout_sec);
+  tc->timeout.tv_nsec =
+      (long) ((timeout_sec - floor (timeout_sec)) * (double) NANOS_PER_SECONDS);
+
   tc->tflst = check_list_create ();
   tc->unch_sflst = check_list_create ();
   tc->ch_sflst = check_list_create ();
@@ -119,16 +154,16 @@ tcase_create (const char *name)
 static void
 tcase_free (TCase * tc)
 {
-  list_apply (tc->tflst, free);
-  list_apply (tc->unch_sflst, free);
-  list_apply (tc->ch_sflst, free);
-  list_apply (tc->unch_tflst, free);
-  list_apply (tc->ch_tflst, free);
-  list_free (tc->tflst);
-  list_free (tc->unch_sflst);
-  list_free (tc->ch_sflst);
-  list_free (tc->unch_tflst);
-  list_free (tc->ch_tflst);
+  check_list_apply (tc->tflst, free);
+  check_list_apply (tc->unch_sflst, free);
+  check_list_apply (tc->ch_sflst, free);
+  check_list_apply (tc->unch_tflst, free);
+  check_list_apply (tc->ch_tflst, free);
+  check_list_free (tc->tflst);
+  check_list_free (tc->unch_sflst);
+  check_list_free (tc->ch_sflst);
+  check_list_free (tc->unch_tflst);
+  check_list_free (tc->ch_tflst);
 
   free (tc);
 }
@@ -138,7 +173,7 @@ suite_add_tcase (Suite * s, TCase * tc)
 {
   if (s == NULL || tc == NULL)
     return;
-  list_add_end (s->tclst, tc);
+  check_list_add_end (s->tclst, tc);
 }
 
 void
@@ -146,23 +181,25 @@ _tcase_add_test (TCase * tc, TFun fn, const char *name, int _signal,
     int allowed_exit_value, int start, int end)
 {
   TF *tf;
+
   if (tc == NULL || fn == NULL || name == NULL)
     return;
-  tf = emalloc (sizeof (TF));   /* freed in tcase_free */
+  tf = (TF *) emalloc (sizeof (TF));    /* freed in tcase_free */
   tf->fn = fn;
   tf->loop_start = start;
   tf->loop_end = end;
   tf->signal = _signal;         /* 0 means no signal expected */
-  tf->allowed_exit_value = allowed_exit_value;  /* 0 is default successful exit */
+  tf->allowed_exit_value = (WEXITSTATUS_MASK & allowed_exit_value);     /* 0 is default successful exit */
   tf->name = name;
-  list_add_end (tc->tflst, tf);
+  check_list_add_end (tc->tflst, tf);
 }
 
 static Fixture *
 fixture_create (SFun fun, int ischecked)
 {
   Fixture *f;
-  f = emalloc (sizeof (Fixture));
+
+  f = (Fixture *) emalloc (sizeof (Fixture));
   f->fun = fun;
   f->ischecked = ischecked;
 
@@ -186,33 +223,48 @@ tcase_add_fixture (TCase * tc, SFun setup, SFun teardown, int ischecked)
 {
   if (setup) {
     if (ischecked)
-      list_add_end (tc->ch_sflst, fixture_create (setup, ischecked));
+      check_list_add_end (tc->ch_sflst, fixture_create (setup, ischecked));
     else
-      list_add_end (tc->unch_sflst, fixture_create (setup, ischecked));
+      check_list_add_end (tc->unch_sflst, fixture_create (setup, ischecked));
   }
 
   /* Add teardowns at front so they are run in reverse order. */
   if (teardown) {
     if (ischecked)
-      list_add_front (tc->ch_tflst, fixture_create (teardown, ischecked));
+      check_list_add_front (tc->ch_tflst, fixture_create (teardown, ischecked));
     else
-      list_add_front (tc->unch_tflst, fixture_create (teardown, ischecked));
+      check_list_add_front (tc->unch_tflst,
+          fixture_create (teardown, ischecked));
   }
 }
 
 void
-tcase_set_timeout (TCase * tc, int timeout)
+tcase_set_timeout (TCase * tc, double timeout)
 {
+#if defined(HAVE_FORK)
   if (timeout >= 0) {
     char *env = getenv ("CK_TIMEOUT_MULTIPLIER");
+
     if (env != NULL) {
-      int tmp = atoi (env);
-      if (tmp >= 0) {
+      char *endptr = NULL;
+      double tmp = strtod (env, &endptr);
+
+      if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
         timeout = timeout * tmp;
       }
     }
-    tc->timeout = timeout;
+
+    tc->timeout.tv_sec = (time_t) floor (timeout);
+    tc->timeout.tv_nsec =
+        (long) ((timeout - floor (timeout)) * (double) NANOS_PER_SECONDS);
   }
+#else
+  (void) tc;
+  (void) timeout;
+  eprintf
+      ("This version does not support timeouts, as fork is not supported",
+      __FILE__, __LINE__);
+#endif /* HAVE_FORK */
 }
 
 void
@@ -230,44 +282,57 @@ _mark_point (const char *file, int line)
 }
 
 void
-_fail_unless (int result, const char *file, int line, const char *expr, ...)
+_ck_assert_failed (const char *file, int line, const char *expr, ...)
 {
   const char *msg;
+  va_list ap;
+  char buf[BUFSIZ];
 
   send_loc_info (file, line);
-  if (!result) {
-    va_list ap;
-    char buf[BUFSIZ];
-
-    va_start (ap, expr);
-    msg = (const char *) va_arg (ap, char *);
-    if (msg == NULL)
-      msg = expr;
-    vsnprintf (buf, BUFSIZ, msg, ap);
-    va_end (ap);
-    send_failure_info (buf);
-    if (cur_fork_status () == CK_FORK) {
-#ifdef _POSIX_VERSION
-      _exit (1);
-#endif /* _POSIX_VERSION */
-    }
+
+  va_start (ap, expr);
+  msg = (const char *) va_arg (ap, char *);
+
+  if (msg == NULL)
+    msg = expr;
+  vsnprintf (buf, BUFSIZ, msg, ap);
+  va_end (ap);
+  send_failure_info (buf);
+  if (cur_fork_status () == CK_FORK) {
+#if defined(HAVE_FORK) && HAVE_FORK==1
+    _exit (1);
+#endif /* HAVE_FORK */
+  } else {
+    longjmp (error_jmp_buffer, 1);
   }
 }
 
 SRunner *
 srunner_create (Suite * s)
 {
-  SRunner *sr = emalloc (sizeof (SRunner));     /* freed in srunner_free */
+  SRunner *sr = (SRunner *) emalloc (sizeof (SRunner)); /* freed in srunner_free */
+
   sr->slst = check_list_create ();
   if (s != NULL)
-    list_add_end (sr->slst, s);
-  sr->stats = emalloc (sizeof (TestStats));     /* freed in srunner_free */
+    check_list_add_end (sr->slst, s);
+  sr->stats = (TestStats *) emalloc (sizeof (TestStats));       /* freed in srunner_free */
   sr->stats->n_checked = sr->stats->n_failed = sr->stats->n_errors = 0;
   sr->resultlst = check_list_create ();
   sr->log_fname = NULL;
   sr->xml_fname = NULL;
+  sr->tap_fname = NULL;
   sr->loglst = NULL;
+
+#if defined(HAVE_FORK)
   sr->fstat = CK_FORK_GETENV;
+#else
+  /*
+   * Overriding the default of running tests in fork mode,
+   * as this system does not have fork()
+   */
+  sr->fstat = CK_NOFORK;
+#endif /* HAVE_FORK */
+
   return sr;
 }
 
@@ -277,7 +342,7 @@ srunner_add_suite (SRunner * sr, Suite * s)
   if (s == NULL)
     return;
 
-  list_add_end (sr->slst, s);
+  check_list_add_end (sr->slst, s);
 }
 
 void
@@ -285,24 +350,23 @@ srunner_free (SRunner * sr)
 {
   List *l;
   TestResult *tr;
+
   if (sr == NULL)
     return;
 
   free (sr->stats);
   l = sr->slst;
-  for (list_front (l); !list_at_end (l); list_advance (l)) {
-    suite_free (list_val (l));
+  for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
+    suite_free ((Suite *) check_list_val (l));
   }
-  list_free (sr->slst);
+  check_list_free (sr->slst);
 
   l = sr->resultlst;
-  for (list_front (l); !list_at_end (l); list_advance (l)) {
-    tr = list_val (l);
-    free (tr->file);
-    free (tr->msg);
-    free (tr);
+  for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
+    tr = (TestResult *) check_list_val (l);
+    tr_free (tr);
   }
-  list_free (sr->resultlst);
+  check_list_free (sr->resultlst);
 
   free (sr);
 }
@@ -325,11 +389,16 @@ srunner_failures (SRunner * sr)
   int i = 0;
   TestResult **trarray;
   List *rlst;
-  trarray = malloc (sizeof (trarray[0]) * srunner_ntests_failed (sr));
+
+  trarray =
+      (TestResult **) emalloc (sizeof (trarray[0]) *
+      srunner_ntests_failed (sr));
 
   rlst = sr->resultlst;
-  for (list_front (rlst); !list_at_end (rlst); list_advance (rlst)) {
-    TestResult *tr = list_val (rlst);
+  for (check_list_front (rlst); !check_list_at_end (rlst);
+      check_list_advance (rlst)) {
+    TestResult *tr = (TestResult *) check_list_val (rlst);
+
     if (non_pass (tr->rtype))
       trarray[i++] = tr;
 
@@ -344,11 +413,13 @@ srunner_results (SRunner * sr)
   TestResult **trarray;
   List *rlst;
 
-  trarray = malloc (sizeof (trarray[0]) * srunner_ntests_run (sr));
+  trarray =
+      (TestResult **) emalloc (sizeof (trarray[0]) * srunner_ntests_run (sr));
 
   rlst = sr->resultlst;
-  for (list_front (rlst); !list_at_end (rlst); list_advance (rlst)) {
-    trarray[i++] = list_val (rlst);
+  for (check_list_front (rlst); !check_list_at_end (rlst);
+      check_list_advance (rlst)) {
+    trarray[i++] = (TestResult *) check_list_val (rlst);
   }
   return trarray;
 }
@@ -364,17 +435,11 @@ tr_create (void)
 {
   TestResult *tr;
 
-  tr = emalloc (sizeof (TestResult));
+  tr = (TestResult *) emalloc (sizeof (TestResult));
   tr_init (tr);
   return tr;
 }
 
-void
-tr_reset (TestResult * tr)
-{
-  tr_init (tr);
-}
-
 static void
 tr_init (TestResult * tr)
 {
@@ -385,6 +450,15 @@ tr_init (TestResult * tr)
   tr->file = NULL;
   tr->tcname = NULL;
   tr->tname = NULL;
+  tr->duration = -1;
+}
+
+void
+tr_free (TestResult * tr)
+{
+  free (tr->file);
+  free (tr->msg);
+  free (tr);
 }
 
 
@@ -424,7 +498,7 @@ tr_tcname (TestResult * tr)
   return tr->tcname;
 }
 
-static int _fstat = CK_FORK;
+static enum fork_status _fstat = CK_FORK;
 
 void
 set_fork_status (enum fork_status fstat)
@@ -440,3 +514,41 @@ cur_fork_status (void)
 {
   return _fstat;
 }
+
+/**
+ * Not all systems support the same clockid_t's. This call checks
+ * if the CLOCK_MONOTONIC clockid_t is valid. If so, that is returned,
+ * otherwise, CLOCK_REALTIME is returned.
+ *
+ * The clockid_t that was found to work on the first call is
+ * cached for subsequent calls.
+ */
+clockid_t
+check_get_clockid ()
+{
+  static clockid_t clockid = -1;
+
+  if (clockid == -1) {
+/*
+ * Only check if we have librt available. Otherwise, the clockid
+ * will be ignored anyway, as the clock_gettime() and
+ * timer_create() functions will be re-implemented in libcompat.
+ * Worse, if librt and alarm() are unavailable, this check
+ * will result in an assert(0).
+ */
+#ifdef HAVE_LIBRT
+    timer_t timerid;
+
+    if (timer_create (CLOCK_MONOTONIC, NULL, &timerid) == 0) {
+      timer_delete (timerid);
+      clockid = CLOCK_MONOTONIC;
+    } else {
+      clockid = CLOCK_REALTIME;
+    }
+#else
+    clockid = CLOCK_MONOTONIC;
+#endif
+  }
+
+  return clockid;
+}
index 3741ad0..e8de6a6 100644 (file)
@@ -15,8 +15,8 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
  */
 
 #ifndef CHECK_H
 #include <stddef.h>
 #include <string.h>
 
-/* Check: a unit test framework for C
-
-   Check is a unit test framework for C. It features a simple
-   interface for defining unit tests, putting little in the way of the
-   developer. Tests are run in a separate address space, so Check can
-   catch both assertion failures and code errors that cause
-   segmentation faults or other signals. The output from unit tests
-   can be used within source code editors and IDEs.
-
-   Unit tests are created with the START_TEST/END_TEST macro
-   pair. The fail_unless and fail macros are used for creating
-   checks within unit tests; the mark_point macro is useful for
-   trapping the location of signals and/or early exits.
-
-
-   Test cases are created with tcase_create, unit tests are added
-   with tcase_add_test
-
-
-   Suites are created with suite_create; test cases are added
-   with suite_add_tcase
-
-   Suites are run through an SRunner, which is created with
-   srunner_create. Additional suites can be added to an SRunner with
-   srunner_add_suite. An SRunner is freed with srunner_free, which also
-   frees all suites added to the runner. 
-
-   Use srunner_run_all to run a suite and print results.
+#include <check_stdint.h>
 
+/*
    Macros and functions starting with _ (underscore) are internal and
    may change without notice. You have been warned!.
-
 */
 
 
@@ -65,7 +38,6 @@
 #define CK_CPPEND }
 CK_CPPSTART
 #endif
-
 #if defined(__GNUC__) && defined(__GNUC_MINOR__)
 #define GCC_VERSION_AT_LEAST(major, minor) \
 ((__GNUC__ > (major)) || \
@@ -73,346 +45,1198 @@ CK_CPPSTART
 #else
 #define GCC_VERSION_AT_LEAST(major, minor) 0
 #endif
-
 #if GCC_VERSION_AT_LEAST(2,95)
 #define CK_ATTRIBUTE_UNUSED __attribute__ ((unused))
 #else
-#define CK_ATTRIBUTE_UNUSED              
+#define CK_ATTRIBUTE_UNUSED
 #endif /* GCC 2.95 */
-
+#if GCC_VERSION_AT_LEAST(2,5)
+#define CK_ATTRIBUTE_NORETURN __attribute__ ((noreturn))
+#else
+#define CK_ATTRIBUTE_NORETURN
+#endif /* GCC 2.5 */
 #include <sys/types.h>
-
-/* Used to create the linker script for hiding lib-local symbols. Shall
-   be put directly in front of the exported symbol. */
+/*
+ * Used to create the linker script for hiding lib-local symbols. Shall
+ * be put directly in front of the exported symbol.
+ */
 #define CK_EXPORT
-
+/*
+ * Used for MSVC to create the export attribute
+ * CK_DLL_EXP is defined during the compilation of the library
+ * on the command line.
+ */
+#ifndef CK_DLL_EXP
+#define CK_DLL_EXP
+#endif
 /* check version numbers */
-  
 #define CHECK_MAJOR_VERSION (@CHECK_MAJOR_VERSION@)
 #define CHECK_MINOR_VERSION (@CHECK_MINOR_VERSION@)
 #define CHECK_MICRO_VERSION (@CHECK_MICRO_VERSION@)
-
-extern int CK_EXPORT check_major_version;
-extern int CK_EXPORT check_minor_version;
-extern int CK_EXPORT check_micro_version;
+CK_DLL_EXP extern int CK_EXPORT check_major_version;
+CK_DLL_EXP extern int CK_EXPORT check_minor_version;
+CK_DLL_EXP extern int CK_EXPORT check_micro_version;
 
 #ifndef NULL
 #define NULL ((void*)0)
 #endif
 
-/* opaque type for a test case
-
-   A TCase represents a test case.  Create with tcase_create, free
-   with tcase_free.  For the moment, test cases can only be run
-   through a suite
+/**
+ * Type for a test case
+ *
+ * A TCase represents a test case.  Create with tcase_create, free
+ * with tcase_free.  For the moment, test cases can only be run
+ * through a suite
 */
-typedef struct TCase TCase; 
+typedef struct TCase TCase;
 
-/* type for a test function */
+/**
+ * Type for a test function
+ */
 typedef void (*TFun) (int);
 
-/* type for a setup/teardown function */
+/**
+ * Type for a setup/teardown function
+ */
 typedef void (*SFun) (void);
-/* Opaque type for a test suite */
+
+/**
+ * Type for a test suite
+ */
 typedef struct Suite Suite;
-/* Creates a test suite with the given name */
-Suite * CK_EXPORT suite_create (const char *name);
 
-/* Add a test case to a suite */
-void CK_EXPORT suite_add_tcase (Suite *s, TCase *tc);
+/**
+ * Creates a test suite with the given name.
+ *
+ * Create a suite, which will contain test cases. Once
+ * created, use suite_add_tcase() to add test cases.
+ * When finished, create a suite runner from the
+ * suite using srunner_create()
+ *
+ * @param name name of the suite
+ *
+ * @return suite
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP Suite *CK_EXPORT suite_create (const char *name);
+
+/**
+ * Determines whether a given test suite contains a case named after a
+ * given string.
+ *
+ * @param s suite to check
+ * @param tcname test case to look for
+ *
+ * @return 1 iff the given test case is within the given suite;
+ *          0 otherwise
+ *
+ * @since 0.9.9
+ */
+CK_DLL_EXP int CK_EXPORT suite_tcase (Suite * s, const char *tcname);
+
+/**
+ * Add a test case to a suite
+ *
+ * @param s suite to add test case to
+ * @param tc test case to add to suite
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP void CK_EXPORT suite_add_tcase (Suite * s, TCase * tc);
 
-/* Create a test case */
-TCase * CK_EXPORT tcase_create (const char *name);
+/**
+ * Create a test case.
+ *
+ * Once created, tests can be added with the tcase_add_test()
+ * function, and the test case assigned to a suite with the
+ * suite_add_tcase() function.
+ *
+ * @param name name of the test case
+ *
+ * @return test case containing no tests
+ *
+ * @since 0.6.0
+ * */
+CK_DLL_EXP TCase *CK_EXPORT tcase_create (const char *name);
 
-/* Add a test function to a test case (macro version) */
+/**
+ * Add a test function to a test case
+ *
+ * @param tc test case to add test to
+ * @param tf test function to add to test case
+ *
+ * @since 0.6.0
+ * */
 #define tcase_add_test(tc,tf) tcase_add_test_raise_signal(tc,tf,0)
 
-/* Add a test function with signal handling to a test case (macro version) */
+/**
+ * Add a test function with signal handling to a test case
+ *
+ * The added test is expected to terminate by throwing the given signal
+ *
+ * @param tc test case to add test to
+ * @param tf test function to add to test case
+ * @param signal expected signal for test function to throw in order for
+ *                the test to be considered passing
+ *
+ * @since 0.9.2
+ * */
 #define tcase_add_test_raise_signal(tc,tf,signal) \
    _tcase_add_test((tc),(tf),"" # tf "",(signal), 0, 0, 1)
 
-/* Add a test function with an expected exit value to a test case (macro version) */
+/**
+ * Add a test function with an expected exit value to a test case
+ *
+ * The added test is expected to terminate by exiting with the given value
+ *
+ * @param tc test case to add test to
+ * @param tf test function to add to test case
+ * @param expected_exit_value exit value for test function to return in
+ *                             order for the test to be considered passing
+ *
+ * @since 0.9.7
+ */
 #define tcase_add_exit_test(tc, tf, expected_exit_value) \
   _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),0,1)
 
-/* Add a looping test function to a test case (macro version)
-
-   The test will be called in a for(i = s; i < e; i++) loop with each
-   iteration being executed in a new context. The loop variable 'i' is
-   available in the test.
+/**
+ * Add a looping test function to a test case
+ *
+ * The test will be called in a for(i = s; i < e; i++) loop with each
+ * iteration being executed in a new context. The loop variable 'i' is
+ * available in the test.
+ *
+ * @param tc test case to add test to
+ * @param tf function to add to test case
+ * @param s starting index for value "i" in test
+ * @param e ending index for value "i" in test
+ *
+ * @since 0.9.4
  */
 #define tcase_add_loop_test(tc,tf,s,e) \
   _tcase_add_test((tc),(tf),"" # tf "",0,0,(s),(e))
-/* Signal version of loop test.  
-   FIXME: add a test case; this is untested as part of Check's tests.
+
+/**
+ * Add a looping test function with signal handling to a test case
+ *
+ * The test will be called in a for(i = s; i < e; i++) loop with each
+ * iteration being executed in a new context. The loop variable 'i' is
+ * available in the test.
+ *
+ * The added test is expected to terminate by throwing the given signal
+ *
+ * @param tc test case to add test to
+ * @param tf function to add to test case
+ * @param signal expected signal for test function to throw in order for
+ *                the test to be considered passing
+ * @param s starting index for value "i" in test
+ * @param e ending index for value "i" in test
+ *
+ * @since 0.9.5
  */
 #define tcase_add_loop_test_raise_signal(tc,tf,signal,s,e) \
   _tcase_add_test((tc),(tf),"" # tf "",(signal),0,(s),(e))
 
-/* allowed exit value version of loop test. */
+/**
+ * Add a looping test function with an expected exit value to a test case
+ *
+ * The test will be called in a for(i = s; i < e; i++) loop with each
+ * iteration being executed in a new context. The loop variable 'i' is
+ * available in the test.
+ *
+ * The added test is expected to terminate by exiting with the given value
+ *
+ * @param tc test case to add test to
+ * @param tf function to add to test case
+ * @param expected_exit_value exit value for test function to return in
+ *                             order for the test to be considered passing
+ * @param s starting index for value "i" in test
+ * @param e ending index for value "i" in test
+ *
+ * @since 0.9.7
+ */
 #define tcase_add_loop_exit_test(tc,tf,expected_exit_value,s,e) \
   _tcase_add_test((tc),(tf),"" # tf "",0,(expected_exit_value),(s),(e))
 
 /* Add a test function to a test case
   (function version -- use this when the macro won't work
 */
-void CK_EXPORT _tcase_add_test (TCase *tc, TFun tf, const char *fname, int _signal, int allowed_exit_value, int start, int end);
+CK_DLL_EXP void CK_EXPORT _tcase_add_test (TCase * tc, TFun tf,
+    const char *fname, int _signal, int allowed_exit_value, int start, int end);
 
-/* Add unchecked fixture setup/teardown functions to a test case
-
-   If unchecked fixture functions are run at the start and end of the
-   test case, and not before and after unit tests. Note that unchecked
-   setup/teardown functions are not run in a separate address space,
-   like test functions, and so must not exit or signal (e.g.,
-   segfault)
+/**
+ * Add unchecked fixture setup/teardown functions to a test case
+ *
+ * Unchecked fixture functions are run at the start and end of the
+ * test case, and not before and after unit tests. Further,
+ * unchecked fixture functions are not run in a separate address space,
+ * like test functions, and so must not exit or signal (e.g.,
+ * segfault).
+ *
+ * Also, when run in CK_NOFORK mode, unchecked fixture functions may
+ * lead to different unit test behavior if unit tests change data
+ * setup by the fixture functions.
+ *
+ * Note that if a setup function fails, the remaining setup functions
+ * will be omitted, as will the test case and the teardown functions.
+ * If a teardown function fails the remaining teardown functins will be
+ * omitted.
+ *
+ * @param tc test case to add unchecked fixture setup/teardown to
+ * @param setup function to add to be executed before the test case;
+ *               if NULL no setup function is added
+ * @param teardown function to add to be executed after the test case;
+ *               if NULL no teardown function is added
+ * @since 0.8.0
+ */
+CK_DLL_EXP void CK_EXPORT tcase_add_unchecked_fixture (TCase * tc, SFun setup,
+    SFun teardown);
 
-   Also, when run in CK_NOFORK mode, unchecked fixture functions may
-   lead to different unit test behavior IF unit tests change data
-   setup by the fixture functions.
+/**
+ * Add checked fixture setup/teardown functions to a test case
+ *
+ * Checked fixture functions are run before and after each unit test inside
+ * of the address space of the test. Thus, if using CK_FORK
+ * mode the separate process running the unit test will survive signals
+ * or unexpected exits in the fixture function. Also, if the setup
+ * function is idempotent, unit test behavior will be the same in
+ * CK_FORK and CK_NOFORK modes.
+ *
+ * However, since fixture functions are run before and after each unit
+ * test, they should not be expensive code.
+ *
+ * Note that if a setup function fails, the remaining setup functions
+ * will be omitted, as will the test and the teardown functions. If a
+ * teardown function fails the remaining teardown functins will be
+ * omitted.
+ *
+ * @param tc test case to add checked fixture setup/teardown to
+ * @param setup function to add to be executed before each unit test in
+ *               the test case;  if NULL no setup function is added
+ * @param teardown function to add to be executed after each unit test in
+ *               the test case; if NULL no teardown function is added
+ *
+ * @since 0.8.0
 */
-void CK_EXPORT tcase_add_unchecked_fixture (TCase *tc, SFun setup, SFun teardown);
-
-/* Add fixture setup/teardown functions to a test case
+CK_DLL_EXP void CK_EXPORT tcase_add_checked_fixture (TCase * tc, SFun setup,
+    SFun teardown);
 
-   Checked fixture functions are run before and after unit
-   tests. Unlike unchecked fixture functions, checked fixture
-   functions are run in the same separate address space as the test
-   program, and thus the test function will survive signals or
-   unexpected exits in the fixture function. Also, IF the setup
-   function is idempotent, unit test behavior will be the same in
-   CK_FORK and CK_NOFORK modes.
-
-   However, since fixture functions are run before and after each unit
-   test, they should not be expensive code.
-
-*/ 
-void CK_EXPORT tcase_add_checked_fixture (TCase *tc, SFun setup, SFun teardown);
+/**
+ * Set the timeout for all tests in a test case.
+ *
+ * A test that lasts longer than the timeout (in seconds) will be killed
+ * and thus fail with an error.
+ *
+ * If not set, the default timeout is one assigned at compile time. If
+ * the environment variable CK_DEFAULT_TIMEOUT is defined and no timeout
+ * is set, the value in the environment variable is used.
+ *
+ * @param tc test case to assign timeout to
+ * @param timeout to use, in seconds. If the value contains a decimal
+ *                 portion, but no high resolution timer is available,
+ *                 the value is rounded up to the nearest second.
+ *
+ * @since 0.9.2
+ */
+CK_DLL_EXP void CK_EXPORT tcase_set_timeout (TCase * tc, double timeout);
 
-/* Set the timeout for all tests in a test case. A test that lasts longer
-   than the timeout (in seconds) will be killed and thus fail with an error.
-   The timeout can also be set globaly with the environment variable
-   CK_DEFAULT_TIMEOUT, the specific setting always takes precedence.
-*/
-void CK_EXPORT tcase_set_timeout (TCase *tc, int timeout);
 /* Internal function to mark the start of a test function */
-void CK_EXPORT tcase_fn_start (const char *fname, const char *file, int line);
+CK_DLL_EXP void CK_EXPORT tcase_fn_start (const char *fname, const char *file,
+    int line);
 
-/* Start a unit test with START_TEST(unit_name), end with END_TEST
-   One must use braces within a START_/END_ pair to declare new variables
-*/ 
+/**
+ * Start a unit test with START_TEST(unit_name), end with END_TEST.
+ *
+ * One must use braces within a START_/END_ pair to declare new variables
+ *
+ * @since 0.6.0
+ */
 #define START_TEST(__testname)\
 static void __testname (int _i CK_ATTRIBUTE_UNUSED)\
 {\
   tcase_fn_start (""# __testname, __FILE__, __LINE__);
 
-/* End a unit test */
+/**
+ *  End a unit test
+ *
+ * @since 0.6.0
+ */
 #define END_TEST }
 
-/* Fail the test case unless expr is true */
-/* The space before the comma sign before ## is essential to be compatible
-   with gcc 2.95.3 and earlier.
-*/
-#define fail_unless(expr, ...)\
-        _fail_unless(expr, __FILE__, __LINE__,\
-        "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL)
-
-/* Fail the test case if expr is true */
-/* The space before the comma sign before ## is essential to be compatible
-   with gcc 2.95.3 and earlier.
-*/
+/*
+ * Fail the test case unless expr is false
+ *
+ * This call is deprecated.
+ */
+#define fail_unless ck_assert_msg
 
-/* FIXME: these macros may conflict with C89 if expr is 
-   FIXME:   strcmp (str1, str2) due to excessive string length. */
+/*
+ * Fail the test case if expr is false
+ *
+ * This call is deprecated.
+ *
+ * NOTE: The space before the comma sign before ## is essential to be compatible
+ * with gcc 2.95.3 and earlier.
+ * FIXME: these macros may conflict with C89 if expr is
+ * FIXME:   strcmp (str1, str2) due to excessive string length.
+ */
 #define fail_if(expr, ...)\
-        _fail_unless(!(expr), __FILE__, __LINE__,\
-        "Failure '"#expr"' occured" , ## __VA_ARGS__, NULL)
+  (expr) ? \
+     _ck_assert_failed(__FILE__, __LINE__, "Failure '"#expr"' occurred" , ## __VA_ARGS__, NULL) \
+     : _mark_point(__FILE__, __LINE__)
 
-/* Always fail */
-#define fail(...) _fail_unless(0, __FILE__, __LINE__, "Failed", __VA_ARGS__, NULL)
+/*
+ * Fail the test
+ *
+ * This call is deprecated.
+ */
+#define fail ck_abort_msg
 
-/* Non macro version of #fail_unless, with more complicated interface */
-void CK_EXPORT _fail_unless (int result, const char *file,
-                             int line, const char *expr, ...);
+/*
+ * This is called whenever an assertion fails.
+ * Note that it only has the noreturn modifier when
+ * using fork. If fork is unavailable, the function
+ * calls longjmp() when a test assertion fails. Marking
+ * the function as noreturn causes gcc to make assumptions
+ * which are not valid, as longjmp() is like a return.
+ */
+#if @HAVE_FORK@
+CK_DLL_EXP void CK_EXPORT
+_ck_assert_failed (const char *file, int line, const char *expr, ...)
+    CK_ATTRIBUTE_NORETURN;
+#else
+CK_DLL_EXP void CK_EXPORT _ck_assert_failed (const char *file, int line,
+    const char *expr, ...);
+#endif
 
-/* New check fail API. */
-#define ck_abort() ck_abort_msg(NULL)
-#define ck_abort_msg fail
-#define ck_assert(C) ck_assert_msg(C, NULL)
-#define ck_assert_msg fail_unless
+/**
+ * Fail the test if expression is false
+ *
+ * @param expr expression to evaluate
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert(expr) ck_assert_msg(expr, NULL)
 
-/* Integer comparsion macros with improved output compared to fail_unless(). */
-/* O may be any comparion operator. */
-#define _ck_assert_int(X, O, Y) ck_assert_msg((X) O (Y), "Assertion '"#X#O#Y"' failed: "#X"==%d, "#Y"==%d", X, Y) 
-#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y) 
-#define ck_assert_int_ne(X, Y) _ck_assert_int(X, !=, Y) 
+/* The space before the comma sign before ## is essential to be compatible
+   with gcc 2.95.3 and earlier.
+*/
+/**
+ * Fail the test if the expression is false; print message on failure
+ *
+ * @param expr expression to evaluate
+ * @param ... message to print (in printf format) if expression is false
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_msg(expr, ...) \
+  (expr) ? \
+     _mark_point(__FILE__, __LINE__) : \
+     _ck_assert_failed(__FILE__, __LINE__, "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL)
 
-/* String comparsion macros with improved output compared to fail_unless() */
-#define _ck_assert_str(C, X, O, Y) ck_assert_msg(C, "Assertion '"#X#O#Y"' failed: "#X"==\"%s\", "#Y"==\"%s\"", X, Y) 
-#define ck_assert_str_eq(X, Y) _ck_assert_str(!strcmp(X, Y), X, ==, Y)
-#define ck_assert_str_ne(X, Y) _ck_assert_str(strcmp(X, Y), X, !=, Y)
+/**
+ * Unconditionally fail the test
+ *
+ * @note Once called, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_abort() ck_abort_msg(NULL)
+/**
+ * Unconditionally fail the test; print a message
+ *
+ * @param ... message to print (in printf format)
+ *
+ * @note Once called, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_abort_msg(...) _ck_assert_failed(__FILE__, __LINE__, "Failed" , ## __VA_ARGS__, NULL)
+
+/* Signed and unsigned integer comparison macros with improved output compared to ck_assert(). */
+/* OP may be any comparison operator. */
+#define _ck_assert_int(X, OP, Y) do { \
+  intmax_t _ck_x = (X); \
+  intmax_t _ck_y = (Y); \
+  ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s==%jd, %s==%jd", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
+} while (0)
+
+/**
+ * Check two signed integers to determine if X==Y
+ *
+ * If not X==Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
+/**
+ * Check two signed integers to determine if X!=Y
+ *
+ * If not X!=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_int_ne(X, Y) _ck_assert_int(X, !=, Y)
+/**
+ * Check two signed integers to determine if X<Y
+ *
+ * If not X<Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_int_lt(X, Y) _ck_assert_int(X, <, Y)
+/**
+ * Check two signed integers to determine if X<=Y
+ *
+ * If not X<=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_int_le(X, Y) _ck_assert_int(X, <=, Y)
+/**
+ * Check two signed integers to determine if X>Y
+ *
+ * If not X>Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_int_gt(X, Y) _ck_assert_int(X, >, Y)
+/**
+ * Check two signed integers to determine if X>=Y
+ *
+ * If not X>=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_int_ge(X, Y) _ck_assert_int(X, >=, Y)
+
+#define _ck_assert_uint(X, OP, Y) do { \
+  uintmax_t _ck_x = (X); \
+  uintmax_t _ck_y = (Y); \
+  ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s==%ju, %s==%ju", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
+} while (0)
+/**
+ * Check two unsigned integers to determine if X==Y
+ *
+ * If not X==Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_eq(X, Y) _ck_assert_uint(X, ==, Y)
+/**
+ * Check two unsigned integers to determine if X!=Y
+ *
+ * If not X!=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_ne(X, Y) _ck_assert_uint(X, !=, Y)
+/**
+ * Check two unsigned integers to determine if X<Y
+ *
+ * If not X<Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_lt(X, Y) _ck_assert_uint(X, <, Y)
+/**
+ * Check two unsigned integers to determine if X<=Y
+ *
+ * If not X<=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_le(X, Y) _ck_assert_uint(X, <=, Y)
+/**
+ * Check two unsigned integers to determine if X>Y
+ *
+ * If not X>Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_gt(X, Y) _ck_assert_uint(X, >, Y)
+/**
+ * Check two unsigned integers to determine if X>=Y
+ *
+ * If not X>=Y, the test fails.
+ *
+ * @param X signed integer
+ * @param Y signed integer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_uint_ge(X, Y) _ck_assert_uint(X, >=, Y)
+
+/* String comparison macros with improved output compared to ck_assert() */
+/* OP might be any operator that can be used in '0 OP strcmp(X,Y)' comparison */
+/* The x and y parameter swap in strcmp() is needed to handle >, >=, <, <= operators */
+#define _ck_assert_str(X, OP, Y) do { \
+  const char* _ck_x = (X); \
+  const char* _ck_y = (Y); \
+  ck_assert_msg(0 OP strcmp(_ck_y, _ck_x), \
+    "Assertion '%s' failed: %s==\"%s\", %s==\"%s\"", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
+} while (0)
+/**
+ * Check two strings to determine if 0==strcmp(X,Y)
+ *
+ * If not 0==strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_str_eq(X, Y) _ck_assert_str(X, ==, Y)
+/**
+ * Check two strings to determine if 0!=strcmp(X,Y)
+ *
+ * If not 0!=strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.6
+ */
+#define ck_assert_str_ne(X, Y) _ck_assert_str(X, !=, Y)
+/**
+ * Check two strings to determine if 0<strcmp(X,Y), (e.g. strcmp(X,Y)>0)
+ *
+ * If not 0<strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_str_lt(X, Y) _ck_assert_str(X, <, Y)
+/**
+ * Check two strings to determine if 0<=strcmp(X,Y) (e.g. strcmp(X,Y)>=0)
+ *
+ * If not 0<=strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_str_le(X, Y) _ck_assert_str(X, <=, Y)
+/**
+ * Check two strings to determine if 0<strcmp(X,Y) (e.g. strcmp(X,Y)>0)
+ *
+ * If not 0<strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_str_gt(X, Y) _ck_assert_str(X, >, Y)
+/**
+ * Check two strings to determine if 0>=strcmp(X,Y) (e.g. strcmp(X,Y)<=0)
+ *
+ * If not 0>=strcmp(X,Y), the test fails.
+ *
+ * @param X string
+ * @param Y string to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_str_ge(X, Y) _ck_assert_str(X, >=, Y)
+
+/* Pointer comparison macros with improved output compared to ck_assert(). */
+/* OP may only be == or !=  */
+#define _ck_assert_ptr(X, OP, Y) do { \
+  const void* _ck_x = (X); \
+  const void* _ck_y = (Y); \
+  ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s==%#x, %s==%#x", #X#OP#Y, #X, _ck_x, #Y, _ck_y); \
+} while (0)
+
+/**
+ * Check if two pointers are equal.
+ *
+ * If the two passed pointers are not equal, the test
+ * fails.
+ *
+ * @param X pointer
+ * @param Y pointer to compare against X
+ *
+ * @note If the check fails, the remaining of the test is aborted
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_ptr_eq(X, Y) _ck_assert_ptr(X, ==, Y)
 
+/**
+ * Check if two pointers are not.
+ *
+ * If the two passed pointers are equal, the test fails.
+ *
+ * @param X pointer
+ * @param Y pointer to compare against X
+ *
+ * @since 0.9.10
+ */
+#define ck_assert_ptr_ne(X, Y) _ck_assert_ptr(X, !=, Y)
 
-/* Mark the last point reached in a unit test
-   (useful for tracking down where a segfault, etc. occurs)
+/**
+ * Mark the last point reached in a unit test.
+ *
+ * If the test throws a signal or exits, the location noted with the
+ * failure is the last location of a ck_assert*() or ck_abort() call.
+ * Use mark_point() to record intermediate locations (useful for tracking down
+ * crashes or exits).
+ *
+ * @since 0.6.0
 */
 #define mark_point() _mark_point(__FILE__,__LINE__)
 
 /* Non macro version of #mark_point */
-void CK_EXPORT _mark_point (const char *file, int line);
-
-/* Result of a test */
-enum test_result {
-  CK_TEST_RESULT_INVALID, /* Default value; should not encounter this */
-  CK_PASS, /* Test passed*/
-  CK_FAILURE, /* Test completed but failed */
-  CK_ERROR /* Test failed to complete
-             (unexpected signal or non-zero early exit) */ 
+CK_DLL_EXP void CK_EXPORT _mark_point (const char *file, int line);
+
+/**
+ * Enum describing the possible results of a test
+ */
+enum test_result
+{
+  CK_TEST_RESULT_INVALID,       /**< Default value; should not encounter this */
+  CK_PASS,                      /**< Test passed */
+  CK_FAILURE,                   /**< Test completed but failed */
+  CK_ERROR                      /**< Test failed to complete
+                                   (unexpected signal or non-zero early exit) */
 };
 
-/* Specifies the how much output an SRunner should produce */
-enum print_output {
-  CK_SILENT, /* No output */
-  CK_MINIMAL, /* Only summary output */
-  CK_NORMAL, /* All failed tests */
-  CK_VERBOSE, /* All tests */
-  CK_ENV, /* Look at environment var */
+/**
+ * Enum specifying the verbosity of output a SRunner should produce
+ */
+enum print_output
+{
+  CK_SILENT,                    /**< No output */
+  CK_MINIMAL,                   /**< Only summary output */
+  CK_NORMAL,                    /**< All failed tests */
+  CK_VERBOSE,                   /**< All tests */
+  CK_ENV,                       /**< Look at environment var CK_VERBOSITY
+                                     for what verbosity to use, which can be
+                                     either "silent", "minimal", "normal",
+                                     or "verbose". If the environment variable
+                                     is not set, then CK_NORMAL will be used.*/
 #if @ENABLE_SUBUNIT@
-  CK_SUBUNIT, /* Run as a subunit child process */
+  CK_SUBUNIT,                   /**< Run as a subunit child process */
 #endif
-  CK_LAST
+  CK_LAST                       /**< Not a valid option */
 };
 
-/* Holds state for a running of a test suite */
+/**
+ * Holds state for a running of a test suite
+ */
 typedef struct SRunner SRunner;
 
-/* Opaque type for a test failure */
+/**
+ * Opaque type for a test failure
+ */
 typedef struct TestResult TestResult;
 
-/* accessors for tr fields */
-enum ck_result_ctx {
-  CK_CTX_INVALID, /* Default value; should not encounter this */
-  CK_CTX_SETUP,
-  CK_CTX_TEST,
-  CK_CTX_TEARDOWN
+/**
+ * Enum representing the types of contexts for a test
+ */
+enum ck_result_ctx
+{
+  CK_CTX_INVALID,               /**< Default value; should not encounter this */
+  CK_CTX_SETUP,                 /**< Setup before a test */
+  CK_CTX_TEST,                  /**< Body of test itself */
+  CK_CTX_TEARDOWN               /**< Teardown after a test */
 };
 
-/* Type of result */
-int CK_EXPORT tr_rtype (TestResult *tr);
-/* Context in which the result occurred */ 
-enum ck_result_ctx CK_EXPORT tr_ctx (TestResult *tr); 
-/* Failure message */
-const char * CK_EXPORT tr_msg (TestResult *tr);
-/* Line number at which failure occured */
-int CK_EXPORT tr_lno (TestResult *tr);
-/* File name at which failure occured */
-const char * CK_EXPORT tr_lfile (TestResult *tr);
-/* Test case in which unit test was run */
-const char * CK_EXPORT tr_tcname (TestResult *tr);
-
-/* Creates an SRunner for the given suite */
-SRunner * CK_EXPORT srunner_create (Suite *s);
-
-/* Adds a Suite to an SRunner */
-void CK_EXPORT srunner_add_suite (SRunner *sr, Suite *s);
-
-/* Frees an SRunner, all suites added to it and all contained test cases */
-void CK_EXPORT srunner_free (SRunner *sr);
-
-/* Test running */
-
-/* Runs an SRunner, printing results as specified (see enum print_output) */
-void CK_EXPORT srunner_run_all (SRunner *sr, enum print_output print_mode);
-
-/* Next functions are valid only after the suite has been
-   completely run, of course */
-
-/* Number of failed tests in a run suite. Includes failures + errors */
-int CK_EXPORT srunner_ntests_failed (SRunner *sr);
-
-/* Total number of tests run in a run suite */
-int CK_EXPORT srunner_ntests_run (SRunner *sr);
-
-/* Return an array of results for all failures
-  
-   Number of failures is equal to srunner_nfailed_tests.  Memory for
-   the array is malloc'ed and must be freed, but individual TestResults
-   must not
-*/
-TestResult ** CK_EXPORT srunner_failures (SRunner *sr);
+/**
+ * Retrieve type of result that the given test result represents.
+ *
+ * This is a member of test_result, and can represent a
+ * pass, failure, or error.
+ *
+ * @param tr test result to retrieve result from
+ *
+ * @return result of given test
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP int CK_EXPORT tr_rtype (TestResult * tr);
+
+/**
+ * Retrieve context in which the result occurred for the given test result.
+ *
+ * The types of contents include the test setup, teardown, or the
+ * body of the test itself.
+ *
+ * @param tr test result to retrieve context from
+ *
+ * @return context to which the given test result applies
+ *
+ * @since 0.8.0
+ */
+CK_DLL_EXP enum ck_result_ctx CK_EXPORT tr_ctx (TestResult * tr);
+
+/**
+ * Retrieve failure message from test result, if applicable.
+ *
+ * @return pointer to a message, if one exists. NULL otherwise.
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP const char *CK_EXPORT tr_msg (TestResult * tr);
+
+/**
+ * Retrieve line number at which a failure occurred, if applicable.
+ *
+ * @return If the test resulted in a failure, returns the line number
+ *          that the failure occurred on; otherwise returns -1.
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP int CK_EXPORT tr_lno (TestResult * tr);
+
+/**
+ * Retrieve file name at which a failure occurred, if applicable.
+ *
+ * @return If the test resulted in a failure, returns a string
+ *          containing the name of the file where the failure
+ *          occurred; otherwise returns NULL.
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP const char *CK_EXPORT tr_lfile (TestResult * tr);
+
+/**
+ * Retrieve test case name in which a failure occurred, if applicable.
+ *
+ * @return If the test resulted in a failure, returns a string
+ *          containing the name of the test suite where the failure
+ *          occurred; otherwise returns NULL.
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP const char *CK_EXPORT tr_tcname (TestResult * tr);
+
+/**
+ * Creates a suite runner for the given suite.
+ *
+ * Once created, additional suites can be added to the
+ * suite runner using srunner_add_suite(), and the suite runner can be
+ * run with srunner_run_all(). Once finished, the suite runner
+ * must be freed with srunner_free().
+ *
+ * @param s suite to generate a suite runner for
+ *
+ * @return suite runner for the given suite
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP SRunner *CK_EXPORT srunner_create (Suite * s);
+
+/**
+ * Add an additional suite to a suite runner.
+ *
+ * The first suite in a suite runner is always added in srunner_create().
+ * This call adds additional suites to a suite runner.
+ *
+ * @param sr suite runner to add the given suite
+ * @param s suite to add to the given suite runner
+ *
+ * @since 0.7.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_add_suite (SRunner * sr, Suite * s);
+
+/**
+ * Frees a suite runner, including all contained suite and test cases.
+ *
+ * This call is responsible for freeing all resources related to a
+ * suite runner and all contained suites and test cases. Suite and
+ * test cases need not be freed individually, as this call handles that.
+ *
+ * @param sr suite runner to free
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_free (SRunner * sr);
+
+/**
+ * Runs a suite runner and all contained suite, printing results to
+ * stdout as specified by the print_mode.
+ *
+ * In addition to running all suites, if the suite runner has been
+ * configured to output to a log, that is also performed.
+ *
+ * Note that if the CK_RUN_CASE and/or CK_RUN_SUITE environment variables
+ * are defined, then only the named suite and/or test case is run.
+ *
+ * @param sr suite runner to run all suites from
+ * @param print_mode the verbosity in which to report results to stdout
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_run_all (SRunner * sr,
+    enum print_output print_mode);
 
-/* Return an array of results for all run tests
+/**
+ * Run a specific suite or test case from a suite runner, printing results
+ * to stdout as specified by the print_mode.
+ *
+ * In addition to running any applicable suites or test cases, if the
+ * suite runner has been configured to output to a log, that is also
+ * performed.
+ *
+ * @param sr suite runner where the given suite or test case must be
+ * @param sname suite name to run. A NULL means "any suite".
+ * @param tcname test case name to run. A NULL means "any test case"
+ * @param print_mode the verbosity in which to report results to stdout
+ *
+ * @since 0.9.9
+ */
+CK_DLL_EXP void CK_EXPORT srunner_run (SRunner * sr, const char *sname,
+    const char *tcname, enum print_output print_mode);
 
-   Number of results is equal to srunner_ntests_run, and excludes
-   failures due to setup function failure.
 
-   Memory is malloc'ed and must be freed, but individual TestResults
-   must not
-*/  
-TestResult ** CK_EXPORT srunner_results (SRunner *sr);
+/**
+ * Retrieve the number of failed tests executed by a suite runner.
+ *
+ * This value represents both test failures and errors.
+ *
+ * @param sr suite runner to query for all failed tests
+ *
+ * @return number of test failures and errors found by the suite runner
+ *
+ * @since 0.6.1
+ */
+CK_DLL_EXP int CK_EXPORT srunner_ntests_failed (SRunner * sr);
 
-/* Printing */
+/**
+ * Retrieve the total number of tests run by a suite runner.
+ *
+ * @param sr suite runner to query for all tests run
+ *
+ * @return number of all tests run by the suite runner
+ *
+ * @since 0.6.1
+ */
+CK_DLL_EXP int CK_EXPORT srunner_ntests_run (SRunner * sr);
 
-/* Print the results contained in an SRunner */
-void CK_EXPORT srunner_print (SRunner *sr, enum print_output print_mode);
-  
-  
-/* Set a log file to which to write during test running.
+/**
+ * Return an array of results for all failures found by a suite runner.
+ *
+ * Number of results is equal to srunner_nfailed_tests().
+ *
+ * Information about individual results can be queried using:
+ * tr_rtype(), tr_ctx(), tr_msg(), tr_lno(), tr_lfile(), and tr_tcname().
+ *
+ * Memory is malloc'ed and must be freed; however free the entire structure
+ * instead of individual test cases.
+ *
+ * @param sr suite runner to retrieve results from
+ *
+ * @return array of TestResult objects
+ *
+ * @since 0.6.0
+ */
+CK_DLL_EXP TestResult **CK_EXPORT srunner_failures (SRunner * sr);
 
-  Log file setting is an initialize only operation -- it should be
-  done immediatly after SRunner creation, and the log file can't be
-  changed after being set.
+/**
+ * Return an array of results for all tests run by a suite runner.
+ *
+ * Number of results is equal to srunner_ntests_run(), and excludes
+ * failures due to setup function failure.
+ *
+ * Information about individual results can be queried using:
+ * tr_rtype(), tr_ctx(), tr_msg(), tr_lno(), tr_lfile(), and tr_tcname().
+ *
+ * Memory is malloc'ed and must be freed; however free the entire structure
+ * instead of individual test cases.
+ *
+ * @param sr suite runner to retrieve results from
+ *
+ * @return array of TestResult objects
+ *
+ * @since 0.6.1
 */
-void CK_EXPORT srunner_set_log (SRunner *sr, const char *fname);
+CK_DLL_EXP TestResult **CK_EXPORT srunner_results (SRunner * sr);
 
-/* Does the SRunner have a log file? */
-int CK_EXPORT srunner_has_log (SRunner *sr);
+/**
+ * Print the results contained in an SRunner to stdout.
+ *
+ * @param sr suite runner to print results for to stdout
+ * @param print_mode the print_output (verbosity) to use to report
+ *         the result
+ *
+ * @since 0.7.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_print (SRunner * sr,
+    enum print_output print_mode);
 
-/* Return the name of the log file, or NULL if none */
-const char * CK_EXPORT srunner_log_fname (SRunner *sr);
+/**
+ * Set the suite runner to output the result in log format to the
+ * given file.
+ *
+ * Note: log file setting is an initialize only operation -- it should
+ * be done immediately after SRunner creation, and the log file can't be
+ * changed after being set.
+ *
+ * This setting does not conflict with the other log output types;
+ * all logging types can occur concurrently if configured.
+ *
+ * @param sr suite runner to log results of in log format
+ * @param fname file name to output log results to
+ *
+ * @since 0.7.1
+*/
+CK_DLL_EXP void CK_EXPORT srunner_set_log (SRunner * sr, const char *fname);
 
-/* Set a xml file to which to write during test running.
+/**
+ * Checks if the suite runner is assigned a file for log output.
+ *
+ * @param sr suite runner to check
+ *
+ * @return 1 iff the suite runner currently is configured to output
+ *         in log format; 0 otherwise
+ *
+ * @since 0.7.1
+ */
+CK_DLL_EXP int CK_EXPORT srunner_has_log (SRunner * sr);
 
-  XML file setting is an initialize only operation -- it should be
-  done immediatly after SRunner creation, and the XML file can't be
-  changed after being set.
+/**
+ * Retrieves the name of the currently assigned file
+ * for log output, if any exists.
+ *
+ * @return the name of the log file, or NULL if none is configured
+ *
+ * @since 0.7.1
+ */
+CK_DLL_EXP const char *CK_EXPORT srunner_log_fname (SRunner * sr);
+
+/**
+ * Set the suite runner to output the result in XML format to the
+ * given file.
+ *
+ * Note: XML file setting is an initialize only operation -- it should
+ * be done immediately after SRunner creation, and the XML file can't be
+ * changed after being set.
+ *
+ * This setting does not conflict with the other log output types;
+ * all logging types can occur concurrently if configured.
+ *
+ * @param sr suite runner to log results of in XML format
+ * @param fname file name to output XML results to
+ *
+ * @since 0.9.1
 */
-void CK_EXPORT srunner_set_xml (SRunner *sr, const char *fname);
+CK_DLL_EXP void CK_EXPORT srunner_set_xml (SRunner * sr, const char *fname);
+
+/**
+ * Checks if the suite runner is assigned a file for XML output.
+ *
+ * @param sr suite runner to check
+ *
+ * @return 1 iff the suite runner currently is configured to output
+ *         in XML format; 0 otherwise
+ *
+ * @since 0.9.1
+ */
+CK_DLL_EXP int CK_EXPORT srunner_has_xml (SRunner * sr);
 
-/* Does the SRunner have an XML log file? */
-int CK_EXPORT srunner_has_xml (SRunner *sr);
+/**
+ * Retrieves the name of the currently assigned file
+ * for XML output, if any exists.
+ *
+ * @return the name of the XML file, or NULL if none is configured
+ *
+ * @since 0.9.1
+ */
+CK_DLL_EXP const char *CK_EXPORT srunner_xml_fname (SRunner * sr);
 
-/* Return the name of the XML file, or NULL if none */
-const char * CK_EXPORT srunner_xml_fname (SRunner *sr);
+/**
+ * Set the suite runner to output the result in TAP format to the
+ * given file.
+ *
+ * Note: TAP file setting is an initialize only operation -- it should
+ * be done immediately after SRunner creation, and the TAP file can't be
+ * changed after being set.
+ *
+ * This setting does not conflict with the other log output types;
+ * all logging types can occur concurrently if configured.
+ *
+ * @param sr suite runner to log results of in TAP format
+ * @param fname file name to output TAP results to
+ *
+ * @since 0.9.12
+*/
+CK_DLL_EXP void CK_EXPORT srunner_set_tap (SRunner * sr, const char *fname);
 
+/**
+ * Checks if the suite runner is assigned a file for TAP output.
+ *
+ * @param sr suite runner to check
+ *
+ * @return 1 iff the suite runner currently is configured to output
+ *         in TAP format; 0 otherwise
+ *
+ * @since 0.9.12
+ */
+CK_DLL_EXP int CK_EXPORT srunner_has_tap (SRunner * sr);
 
-/* Control forking */
-enum fork_status {
-  CK_FORK_GETENV, /* look in the environment for CK_FORK */
-  CK_FORK,        /* call fork to run tests */
-  CK_NOFORK       /* don't call fork */
+/**
+ * Retrieves the name of the currently assigned file
+ * for TAP output, if any exists.
+ *
+ * @return the name of the TAP file, or NULL if none is configured
+ *
+ * @since 0.9.12
+ */
+CK_DLL_EXP const char *CK_EXPORT srunner_tap_fname (SRunner * sr);
+
+/**
+ * Enum describing the current fork usage.
+ */
+enum fork_status
+{
+  CK_FORK_GETENV,               /**< look in the environment for CK_FORK */
+  CK_FORK,                      /**< call fork to run tests */
+  CK_NOFORK                     /**< don't call fork */
 };
-/* Get the current fork status */
-enum fork_status CK_EXPORT srunner_fork_status (SRunner *sr);
 
-/* Set the current fork status */
-void CK_EXPORT srunner_set_fork_status (SRunner *sr, enum fork_status fstat); 
-  
-/* Fork in a test and make sure messaging and tests work. */
-pid_t CK_EXPORT check_fork(void);
+/**
+ * Retrieve the current fork status for the given suite runner
+ *
+ * @param sr suite runner to check fork status of
+ *
+ * @since 0.8.0
+ */
+CK_DLL_EXP enum fork_status CK_EXPORT srunner_fork_status (SRunner * sr);
 
-/* Wait for the pid and exit. If pid is zero, just exit. */
-void CK_EXPORT check_waitpid_and_exit(pid_t pid);
+/**
+ * Set the fork status for a given suite runner.
+ *
+ * The default fork status is CK_FORK_GETENV, which will look
+ * for the CK_FORK environment variable, which can be set to
+ * "yes" or "no". If the environment variable is not present,
+ * CK_FORK will be used if fork() is available on the system,
+ * otherwise CK_NOFORK is used.
+ *
+ * If set to CK_FORK or CK_NOFORK, the environment variable
+ * if defined is ignored.
+ *
+ * @param sr suite runner to assign the fork status to
+ * @param fstat fork status to assign
+ *
+ * @since 0.8.0
+ */
+CK_DLL_EXP void CK_EXPORT srunner_set_fork_status (SRunner * sr,
+    enum fork_status fstat);
 
-#ifdef __cplusplus 
+/**
+ * Invoke fork() during a test and assign the child to the same
+ * process group that the rest of the test case uses.
+ *
+ * One can invoke fork() directly during a test; however doing so
+ * may not guarantee that any children processes are destroyed once
+ * the test finishes. Once a test has completed, all processes in
+ * the process group will be killed; using this wrapper will prevent
+ * orphan processes.
+ *
+ * @return On success, the PID of the child process is returned in
+ *          the parent, and 0 is returned in the child.  On failure,
+ *          an error will be printed and exit() invoked.
+ *
+ * @since 0.9.3
+ */
+CK_DLL_EXP pid_t CK_EXPORT check_fork (void);
+
+/**
+ * Wait for the pid and exit.
+ *
+ * This is to be used in conjunction with check_fork(). When called,
+ * will wait for the given process to terminate. If the process
+ * exited without error, exit(EXIT_SUCCESS) is invoked; otherwise
+ * exit(EXIT_FAILURE) is invoked.
+ *
+ * @param pid process to wait for, created by check_fork()
+ *
+ * @since 0.9.3
+ */
+CK_DLL_EXP void CK_EXPORT
+check_waitpid_and_exit (pid_t pid)
+    CK_ATTRIBUTE_NORETURN;
+
+#ifdef __cplusplus
 CK_CPPEND
 #endif
-
 #endif /* CHECK_H */
index 247b9ca..c4aebd0 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
-#include "config.h"
+#include "../lib/libcompat.h"
 
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
+#include <setjmp.h>
 
 #include "check_error.h"
 
+/**
+ * Storage for setjmp/longjmp context information used in NOFORK mode
+ */
+jmp_buf error_jmp_buffer;
+
 
 /* FIXME: including a colon at the end is a bad way to indicate an error */
 void
 eprintf (const char *fmt, const char *file, int line, ...)
 {
   va_list args;
+
   fflush (stderr);
 
   fprintf (stderr, "%s:%d: ", file, line);
@@ -53,6 +60,7 @@ void *
 emalloc (size_t n)
 {
   void *p;
+
   p = malloc (n);
   if (p == NULL)
     eprintf ("malloc of %u bytes failed:", __FILE__, __LINE__ - 2, n);
@@ -63,6 +71,7 @@ void *
 erealloc (void *ptr, size_t n)
 {
   void *p;
+
   p = realloc (ptr, n);
   if (p == NULL)
     eprintf ("realloc of %u bytes failed:", __FILE__, __LINE__ - 2, n);
index 3fa0129..b3e8744 100644 (file)
 #ifndef ERROR_H
 #define ERROR_H
 
+#include "../lib/libcompat.h"
+#include <setjmp.h>
+
+extern jmp_buf error_jmp_buffer;
+
 /* Include stdlib.h beforehand */
 
 /* Print error message and die
    If fmt ends in colon, include system error information */
-void eprintf (const char *fmt, const char *file, int line,...);
+void
+eprintf (const char *fmt, const char *file, int line, ...)
+    CK_ATTRIBUTE_NORETURN;
 /* malloc or die */
-void *emalloc(size_t n);
-void *erealloc(void *, size_t n);
+     void *emalloc (size_t n);
+     void *erealloc (void *, size_t n);
 
-#endif /*ERROR_H*/
+#endif /*ERROR_H */
index c76488e..e5ca7e9 100644 (file)
 #ifndef CHECK_IMPL_H
 #define CHECK_IMPL_H
 
-
 /* This header should be included by any module that needs
    to know the implementation details of the check structures
-   Include stdio.h & list.h before this header
+   Include stdio.h, time.h, & list.h before this header
 */
 
-typedef struct TF {
+#define US_PER_SEC 1000000
+#define NANOS_PER_SECONDS 1000000000
+
+/** calculate the difference in useconds out of two "struct timespec"s */
+#define DIFF_IN_USEC(begin, end) \
+  ( (((end).tv_sec - (begin).tv_sec) * US_PER_SEC) + \
+    ((end).tv_nsec/1000) - ((begin).tv_nsec/1000) )
+
+typedef struct TF
+{
   TFun fn;
   int loop_start;
   int loop_end;
   const char *name;
   int signal;
-  unsigned char allowed_exit_value;
+  signed char allowed_exit_value;
 } TF;
 
-struct Suite {
+struct Suite
+{
   const char *name;
-  List *tclst; /* List of test cases */
+  List *tclst;                  /* List of test cases */
 };
 
-typedef struct Fixture 
+typedef struct Fixture
 {
   int ischecked;
   SFun fun;
 } Fixture;
 
-struct TCase {
+struct TCase
+{
   const char *name;
-  int timeout;
-  List *tflst; /* list of test functions */
+  struct timespec timeout;
+  List *tflst;                  /* list of test functions */
   List *unch_sflst;
   List *unch_tflst;
   List *ch_sflst;
   List *ch_tflst;
 };
 
-typedef struct TestStats {
+typedef struct TestStats
+{
   int n_checked;
   int n_failed;
   int n_errors;
 } TestStats;
 
-struct TestResult {
-  enum test_result rtype;     /* Type of result */
-  enum ck_result_ctx ctx;     /* When the result occurred */
-  char *file;    /* File where the test occured */
-  int line;      /* Line number where the test occurred */
-  int iter;      /* The iteration value for looping tests */
-  const char *tcname;  /* Test case that generated the result */
-  const char *tname;  /* Test that generated the result */
-  char *msg;     /* Failure message */
+struct TestResult
+{
+  enum test_result rtype;       /* Type of result */
+  enum ck_result_ctx ctx;       /* When the result occurred */
+  char *file;                   /* File where the test occured */
+  int line;                     /* Line number where the test occurred */
+  int iter;                     /* The iteration value for looping tests */
+  int duration;                 /* duration of this test in microseconds */
+  const char *tcname;           /* Test case that generated the result */
+  const char *tname;            /* Test that generated the result */
+  char *msg;                    /* Failure message */
 };
 
-TestResult *tr_create(void);
-void tr_reset(TestResult *tr);
-
-enum cl_event {
-  CLINITLOG_SR,
-  CLENDLOG_SR,
-  CLSTART_SR,
-  CLSTART_S,
-  CLEND_SR,
-  CLEND_S,
-  CLSTART_T, /* A test case is about to run */
-  CLEND_T
+TestResult *tr_create (void);
+void tr_reset (TestResult * tr);
+void tr_free (TestResult * tr);
+
+enum cl_event
+{
+  CLINITLOG_SR,                 /* Initialize log file */
+  CLENDLOG_SR,                  /* Tests are complete */
+  CLSTART_SR,                   /* Suite runner start */
+  CLSTART_S,                    /* Suite start */
+  CLEND_SR,                     /* Suite runner end */
+  CLEND_S,                      /* Suite end */
+  CLSTART_T,                    /* A test case is about to run */
+  CLEND_T                       /* Test case end */
 };
 
-typedef void (*LFun) (SRunner *, FILE*, enum print_output,
-                     void *, enum cl_event);
+typedef void (*LFun) (SRunner *, FILE *, enum print_output,
+    void *, enum cl_event);
 
-typedef struct Log {
+typedef struct Log
+{
   FILE *lfile;
   LFun lfun;
   int close;
   enum print_output mode;
 } Log;
 
-struct SRunner {
-  List *slst; /* List of Suite objects */
-  TestStats *stats; /* Run statistics */
-  List *resultlst; /* List of unit test results */
-  const char *log_fname; /* name of log file */
-  const char *xml_fname; /* name of xml output file */
-  List *loglst; /* list of Log objects */
-  enum fork_status fstat; /* controls if suites are forked or not
-                            NOTE: Don't use this value directly,
-                            instead use srunner_fork_status */
+struct SRunner
+{
+  List *slst;                   /* List of Suite objects */
+  TestStats *stats;             /* Run statistics */
+  List *resultlst;              /* List of unit test results */
+  const char *log_fname;        /* name of log file */
+  const char *xml_fname;        /* name of xml output file */
+  const char *tap_fname;        /* name of tap output file */
+  List *loglst;                 /* list of Log objects */
+  enum fork_status fstat;       /* controls if suites are forked or not
+                                   NOTE: Don't use this value directly,
+                                   instead use srunner_fork_status */
 };
 
 
-void set_fork_status(enum fork_status fstat);
+void set_fork_status (enum fork_status fstat);
 enum fork_status cur_fork_status (void);
 
+clockid_t check_get_clockid (void);
+
 #endif /* CHECK_IMPL_H */
index c40ab58..1382cfa 100644 (file)
@@ -18,7 +18,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#include "config.h"
+#include "../lib/libcompat.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -35,11 +35,11 @@ enum
 
 struct List
 {
-  int n_elts;
-  int max_elts;
+  unsigned int n_elts;
+  unsigned int max_elts;
   int current;                  /* pointer to the current node */
   int last;                     /* pointer to the node before END */
-  const void **data;
+  void **data;
 };
 
 static void
@@ -47,7 +47,8 @@ maybe_grow (List * lp)
 {
   if (lp->n_elts >= lp->max_elts) {
     lp->max_elts *= LGROW;
-    lp->data = erealloc (lp->data, lp->max_elts * sizeof (lp->data[0]));
+    lp->data =
+        (void **) erealloc (lp->data, lp->max_elts * sizeof (lp->data[0]));
   }
 }
 
@@ -55,16 +56,17 @@ List *
 check_list_create (void)
 {
   List *lp;
-  lp = emalloc (sizeof (List));
+
+  lp = (List *) emalloc (sizeof (List));
   lp->n_elts = 0;
   lp->max_elts = LINIT;
-  lp->data = emalloc (sizeof (lp->data[0]) * LINIT);
+  lp->data = (void **) emalloc (sizeof (lp->data[0]) * LINIT);
   lp->current = lp->last = -1;
   return lp;
 }
 
 void
-list_add_front (List * lp, const void *val)
+check_list_add_front (List * lp, void *val)
 {
   if (lp == NULL)
     return;
@@ -77,7 +79,7 @@ list_add_front (List * lp, const void *val)
 }
 
 void
-list_add_end (List * lp, const void *val)
+check_list_add_end (List * lp, void *val)
 {
   if (lp == NULL)
     return;
@@ -89,7 +91,7 @@ list_add_end (List * lp, const void *val)
 }
 
 int
-list_at_end (List * lp)
+check_list_at_end (List * lp)
 {
   if (lp->current == -1)
     return 1;
@@ -98,7 +100,7 @@ list_at_end (List * lp)
 }
 
 void
-list_front (List * lp)
+check_list_front (List * lp)
 {
   if (lp->current == -1)
     return;
@@ -107,7 +109,7 @@ list_front (List * lp)
 
 
 void
-list_free (List * lp)
+check_list_free (List * lp)
 {
   if (lp == NULL)
     return;
@@ -117,34 +119,34 @@ list_free (List * lp)
 }
 
 void *
-list_val (List * lp)
+check_list_val (List * lp)
 {
   if (lp == NULL)
     return NULL;
   if (lp->current == -1 || lp->current > lp->last)
     return NULL;
 
-  return (void *) lp->data[lp->current];
+  return lp->data[lp->current];
 }
 
 void
-list_advance (List * lp)
+check_list_advance (List * lp)
 {
   if (lp == NULL)
     return;
-  if (list_at_end (lp))
+  if (check_list_at_end (lp))
     return;
   lp->current++;
 }
 
 
 void
-list_apply (List * lp, void (*fp) (void *))
+check_list_apply (List * lp, void (*fp) (void *))
 {
   if (lp == NULL || fp == NULL)
     return;
 
-  for (list_front (lp); !list_at_end (lp); list_advance (lp))
-    fp (list_val (lp));
+  for (check_list_front (lp); !check_list_at_end (lp); check_list_advance (lp))
+    fp (check_list_val (lp));
 
 }
index 7936c19..0270115 100644 (file)
 typedef struct List List;
 
 /* Create an empty list */
-List * check_list_create (void);
+List *check_list_create (void);
 
 /* Is list at end? */
-int list_at_end (List * lp);
+int check_list_at_end (List * lp);
 
 /* Position list at front */
-void list_front(List *lp);
+void check_list_front (List * lp);
 
 /* Add a value to the front of the list,
    positioning newly added value as current value.
    More expensive than list_add_end, as it uses memmove. */
-void list_add_front (List *lp, const void *val);
+void check_list_add_front (List * lp, void *val);
 
 /* Add a value to the end of the list,
    positioning newly added value as current value */
-void list_add_end (List *lp, const void *val);
+void check_list_add_end (List * lp, void *val);
 
 /* Give the value of the current node */
-void *list_val (List * lp);
+void *check_list_val (List * lp);
 
 /* Position the list at the next node */
-void list_advance (List * lp);
+void check_list_advance (List * lp);
 
 /* Free a list, but don't free values */
-void list_free (List * lp);
+void check_list_free (List * lp);
 
-void list_apply (List *lp, void (*fp) (void *));
+void check_list_apply (List * lp, void (*fp) (void *));
 
 
 #endif /* CHECK_LIST_H */
index 5f0dd97..cd1e5b5 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
-#include "config.h"
+#include "../lib/libcompat.h"
 
 #include <stdlib.h>
 #include <stdio.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <time.h>
 #include <check.h>
-#if HAVE_SUBUNIT_CHILD_H
+#if ENABLE_SUBUNIT
 #include <subunit/child.h>
 #endif
 
 #include "check_print.h"
 #include "check_str.h"
 
-/* localtime_r is apparently not available on Windows */
-#ifndef HAVE_LOCALTIME_R
-static struct tm *
-localtime_r (const time_t * clock, struct tm *result)
-{
-  struct tm *now = localtime (clock);
-  if (now == NULL) {
-    return NULL;
-  } else {
-    *result = *now;
-  }
-  return result;
-}
-#endif /* HAVE_DECL_LOCALTIME_R */
+/*
+ * If a log file is specified to be "-", then instead of
+ * opening a file the log output is printed to stdout.
+ */
+#define STDOUT_OVERRIDE_LOG_FILE_NAME "-"
 
 static void srunner_send_evt (SRunner * sr, void *obj, enum cl_event evt);
 
@@ -66,13 +53,17 @@ srunner_set_log (SRunner * sr, const char *fname)
 int
 srunner_has_log (SRunner * sr)
 {
-  return sr->log_fname != NULL;
+  return srunner_log_fname (sr) != NULL;
 }
 
 const char *
 srunner_log_fname (SRunner * sr)
 {
-  return sr->log_fname;
+  /* check if log filename have been set explicitly */
+  if (sr->log_fname != NULL)
+    return sr->log_fname;
+
+  return getenv ("CK_LOG_FILE_NAME");
 }
 
 
@@ -87,20 +78,50 @@ srunner_set_xml (SRunner * sr, const char *fname)
 int
 srunner_has_xml (SRunner * sr)
 {
-  return sr->xml_fname != NULL;
+  return srunner_xml_fname (sr) != NULL;
 }
 
 const char *
 srunner_xml_fname (SRunner * sr)
 {
-  return sr->xml_fname;
+  /* check if XML log filename have been set explicitly */
+  if (sr->xml_fname != NULL) {
+    return sr->xml_fname;
+  }
+
+  return getenv ("CK_XML_LOG_FILE_NAME");
+}
+
+void
+srunner_set_tap (SRunner * sr, const char *fname)
+{
+  if (sr->tap_fname)
+    return;
+  sr->tap_fname = fname;
+}
+
+int
+srunner_has_tap (SRunner * sr)
+{
+  return srunner_tap_fname (sr) != NULL;
+}
+
+const char *
+srunner_tap_fname (SRunner * sr)
+{
+  /* check if tap log filename have been set explicitly */
+  if (sr->tap_fname != NULL) {
+    return sr->tap_fname;
+  }
+
+  return getenv ("CK_TAP_LOG_FILE_NAME");
 }
 
 void
 srunner_register_lfun (SRunner * sr, FILE * lfile, int close,
     LFun lfun, enum print_output printmode)
 {
-  Log *l = emalloc (sizeof (Log));
+  Log *l = (Log *) emalloc (sizeof (Log));
 
   if (printmode == CK_ENV) {
     printmode = get_env_printmode ();
@@ -110,7 +131,7 @@ srunner_register_lfun (SRunner * sr, FILE * lfile, int close,
   l->lfun = lfun;
   l->close = close;
   l->mode = printmode;
-  list_add_end (sr->loglst, l);
+  check_list_add_end (sr->loglst, l);
   return;
 }
 
@@ -142,6 +163,7 @@ void
 log_test_start (SRunner * sr, TCase * tc, TF * tfun)
 {
   char buffer[100];
+
   snprintf (buffer, 99, "%s:%s", tc->name, tfun->name);
   srunner_send_evt (sr, buffer, CLSTART_T);
 }
@@ -157,9 +179,10 @@ srunner_send_evt (SRunner * sr, void *obj, enum cl_event evt)
 {
   List *l;
   Log *lg;
+
   l = sr->loglst;
-  for (list_front (l); !list_at_end (l); list_advance (l)) {
-    lg = list_val (l);
+  for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
+    lg = (Log *) check_list_val (l);
     fflush (lg->lfile);
     lg->lfun (sr, lg->lfile, lg->mode, obj, evt);
     fflush (lg->lfile);
@@ -172,10 +195,6 @@ stdout_lfun (SRunner * sr, FILE * file, enum print_output printmode,
 {
   Suite *s;
 
-  if (printmode == CK_ENV) {
-    printmode = get_env_printmode ();
-  }
-
   switch (evt) {
     case CLINITLOG_SR:
       break;
@@ -187,7 +206,7 @@ stdout_lfun (SRunner * sr, FILE * file, enum print_output printmode,
       }
       break;
     case CLSTART_S:
-      s = obj;
+      s = (Suite *) obj;
       if (printmode > CK_SILENT) {
         fprintf (file, " %s\n", s->name);
       }
@@ -202,7 +221,6 @@ stdout_lfun (SRunner * sr, FILE * file, enum print_output printmode,
       }
       break;
     case CLEND_S:
-      s = obj;
       break;
     case CLSTART_T:
       break;
@@ -231,7 +249,7 @@ lfile_lfun (SRunner * sr, FILE * file,
     case CLSTART_SR:
       break;
     case CLSTART_S:
-      s = obj;
+      s = (Suite *) obj;
       fprintf (file, "Running suite %s\n", s->name);
       break;
     case CLEND_SR:
@@ -239,12 +257,11 @@ lfile_lfun (SRunner * sr, FILE * file,
       srunner_fprint (file, sr, CK_MINIMAL);
       break;
     case CLEND_S:
-      s = obj;
       break;
     case CLSTART_T:
       break;
     case CLEND_T:
-      tr = obj;
+      tr = (TestResult *) obj;
       tr_fprint (file, tr, CK_VERBOSE);
       break;
     default:
@@ -261,47 +278,60 @@ xml_lfun (SRunner * sr CK_ATTRIBUTE_UNUSED, FILE * file,
 {
   TestResult *tr;
   Suite *s;
-  static struct timeval inittv, endtv;
+  static struct timespec ts_start = { 0, 0 };
   static char t[sizeof "yyyy-mm-dd hh:mm:ss"] = { 0 };
 
   if (t[0] == 0) {
+    struct timeval inittv;
     struct tm now;
+
     gettimeofday (&inittv, NULL);
-    localtime_r (&(inittv.tv_sec), &now);
-    strftime (t, sizeof ("yyyy-mm-dd hh:mm:ss"), "%Y-%m-%d %H:%M:%S", &now);
+    clock_gettime (check_get_clockid (), &ts_start);
+    if (localtime_r ((const time_t *) &(inittv.tv_sec), &now) != NULL) {
+      strftime (t, sizeof ("yyyy-mm-dd hh:mm:ss"), "%Y-%m-%d %H:%M:%S", &now);
+    }
   }
 
   switch (evt) {
     case CLINITLOG_SR:
       fprintf (file, "<?xml version=\"1.0\"?>\n");
       fprintf (file,
+          "<?xml-stylesheet type=\"text/xsl\" href=\"http://check.sourceforge.net/xml/check_unittest.xslt\"?>\n");
+      fprintf (file,
           "<testsuites xmlns=\"http://check.sourceforge.net/ns\">\n");
       fprintf (file, "  <datetime>%s</datetime>\n", t);
       break;
     case CLENDLOG_SR:
-      gettimeofday (&endtv, NULL);
-      fprintf (file, "  <duration>%f</duration>\n",
-          (endtv.tv_sec + (float) (endtv.tv_usec) / 1000000) -
-          (inittv.tv_sec + (float) (inittv.tv_usec / 1000000)));
+    {
+      struct timespec ts_end = { 0, 0 };
+      unsigned long duration;
+
+      /* calculate time the test were running */
+      clock_gettime (check_get_clockid (), &ts_end);
+      duration = (unsigned long) DIFF_IN_USEC (ts_start, ts_end);
+      fprintf (file, "  <duration>%lu.%06lu</duration>\n",
+          duration / US_PER_SEC, duration % US_PER_SEC);
       fprintf (file, "</testsuites>\n");
+    }
       break;
     case CLSTART_SR:
       break;
     case CLSTART_S:
-      s = obj;
+      s = (Suite *) obj;
       fprintf (file, "  <suite>\n");
-      fprintf (file, "    <title>%s</title>\n", s->name);
+      fprintf (file, "    <title>");
+      fprint_xml_esc (file, s->name);
+      fprintf (file, "</title>\n");
       break;
     case CLEND_SR:
       break;
     case CLEND_S:
       fprintf (file, "  </suite>\n");
-      s = obj;
       break;
     case CLSTART_T:
       break;
     case CLEND_T:
-      tr = obj;
+      tr = (TestResult *) obj;
       tr_xmlprint (file, tr, CK_VERBOSE);
       break;
     default:
@@ -310,13 +340,55 @@ xml_lfun (SRunner * sr CK_ATTRIBUTE_UNUSED, FILE * file,
 
 }
 
+void
+tap_lfun (SRunner * sr CK_ATTRIBUTE_UNUSED, FILE * file,
+    enum print_output printmode CK_ATTRIBUTE_UNUSED, void *obj,
+    enum cl_event evt)
+{
+  TestResult *tr;
+
+  static int num_tests_run = 0;
+
+  switch (evt) {
+    case CLINITLOG_SR:
+      /* As this is a new log file, reset the number of tests executed */
+      num_tests_run = 0;
+      break;
+    case CLENDLOG_SR:
+      /* Output the test plan as the last line */
+      fprintf (file, "1..%d\n", num_tests_run);
+      fflush (file);
+      break;
+    case CLSTART_SR:
+      break;
+    case CLSTART_S:
+      break;
+    case CLEND_SR:
+      break;
+    case CLEND_S:
+      break;
+    case CLSTART_T:
+      break;
+    case CLEND_T:
+      /* Print the test result to the tap file */
+      num_tests_run += 1;
+      tr = (TestResult *) obj;
+      fprintf (file, "%s %d - %s:%s:%s: %s\n",
+          tr->rtype == CK_PASS ? "ok" : "not ok", num_tests_run,
+          tr->file, tr->tcname, tr->tname, tr->msg);
+      fflush (file);
+      break;
+    default:
+      eprintf ("Bad event type received in tap_lfun", __FILE__, __LINE__);
+  }
+}
+
 #if ENABLE_SUBUNIT
 void
 subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
     void *obj, enum cl_event evt)
 {
   TestResult *tr;
-  Suite *s;
   char const *name;
 
   /* assert(printmode == CK_SUBUNIT); */
@@ -329,7 +401,6 @@ subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
     case CLSTART_SR:
       break;
     case CLSTART_S:
-      s = obj;
       break;
     case CLEND_SR:
       if (printmode > CK_SILENT) {
@@ -338,17 +409,17 @@ subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
       }
       break;
     case CLEND_S:
-      s = obj;
       break;
     case CLSTART_T:
-      name = obj;
+      name = (const char *) obj;
       subunit_test_start (name);
       break;
     case CLEND_T:
-      tr = obj;
+      tr = (TestResult *) obj;
       {
         char *name = ck_strdup_printf ("%s:%s", tr->tcname, tr->tname);
         char *msg = tr_short_str (tr);
+
         switch (tr->rtype) {
           case CK_PASS:
             subunit_test_pass (name);
@@ -359,6 +430,7 @@ subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
           case CK_ERROR:
             subunit_test_error (name, msg);
             break;
+          case CK_TEST_RESULT_INVALID:
           default:
             eprintf ("Bad result type in subunit_lfun", __FILE__, __LINE__);
             free (name);
@@ -372,15 +444,30 @@ subunit_lfun (SRunner * sr, FILE * file, enum print_output printmode,
 }
 #endif
 
+static FILE *
+srunner_open_file (const char *filename)
+{
+  FILE *f = NULL;
+
+  if (strcmp (filename, STDOUT_OVERRIDE_LOG_FILE_NAME) == 0) {
+    f = stdout;
+  } else {
+    f = fopen (filename, "w");
+    if (f == NULL) {
+      eprintf ("Error in call to fopen while opening file %s:", __FILE__,
+          __LINE__ - 2, filename);
+    }
+  }
+  return f;
+}
+
 FILE *
 srunner_open_lfile (SRunner * sr)
 {
   FILE *f = NULL;
+
   if (srunner_has_log (sr)) {
-    f = fopen (sr->log_fname, "w");
-    if (f == NULL)
-      eprintf ("Error in call to fopen while opening log file %s:", __FILE__,
-          __LINE__ - 2, sr->log_fname);
+    f = srunner_open_file (srunner_log_fname (sr));
   }
   return f;
 }
@@ -389,11 +476,20 @@ FILE *
 srunner_open_xmlfile (SRunner * sr)
 {
   FILE *f = NULL;
+
   if (srunner_has_xml (sr)) {
-    f = fopen (sr->xml_fname, "w");
-    if (f == NULL)
-      eprintf ("Error in call to fopen while opening xml file %s:", __FILE__,
-          __LINE__ - 2, sr->xml_fname);
+    f = srunner_open_file (srunner_xml_fname (sr));
+  }
+  return f;
+}
+
+FILE *
+srunner_open_tapfile (SRunner * sr)
+{
+  FILE *f = NULL;
+
+  if (srunner_has_tap (sr)) {
+    f = srunner_open_file (srunner_tap_fname (sr));
   }
   return f;
 }
@@ -402,6 +498,7 @@ void
 srunner_init_logging (SRunner * sr, enum print_output print_mode)
 {
   FILE *f;
+
   sr->loglst = check_list_create ();
 #if ENABLE_SUBUNIT
   if (print_mode != CK_SUBUNIT)
@@ -413,11 +510,15 @@ srunner_init_logging (SRunner * sr, enum print_output print_mode)
 #endif
   f = srunner_open_lfile (sr);
   if (f) {
-    srunner_register_lfun (sr, f, 1, lfile_lfun, print_mode);
+    srunner_register_lfun (sr, f, f != stdout, lfile_lfun, print_mode);
   }
   f = srunner_open_xmlfile (sr);
   if (f) {
-    srunner_register_lfun (sr, f, 2, xml_lfun, print_mode);
+    srunner_register_lfun (sr, f, f != stdout, xml_lfun, print_mode);
+  }
+  f = srunner_open_tapfile (sr);
+  if (f) {
+    srunner_register_lfun (sr, f, f != stdout, tap_lfun, print_mode);
   }
   srunner_send_evt (sr, NULL, CLINITLOG_SR);
 }
@@ -431,16 +532,17 @@ srunner_end_logging (SRunner * sr)
   srunner_send_evt (sr, NULL, CLENDLOG_SR);
 
   l = sr->loglst;
-  for (list_front (l); !list_at_end (l); list_advance (l)) {
-    Log *lg = list_val (l);
+  for (check_list_front (l); !check_list_at_end (l); check_list_advance (l)) {
+    Log *lg = (Log *) check_list_val (l);
+
     if (lg->close) {
       rval = fclose (lg->lfile);
       if (rval != 0)
-        eprintf ("Error in call to fclose while closing log file:", __FILE__,
-            __LINE__ - 2);
+        eprintf ("Error in call to fclose while closing log file:",
+            __FILE__, __LINE__ - 2);
     }
     free (lg);
   }
-  list_free (l);
+  check_list_free (l);
   sr->loglst = NULL;
 }
index 84c9b7c..8578a90 100644 (file)
 #ifndef CHECK_LOG_H
 #define CHECK_LOG_H
 
-void log_srunner_start (SRunner *sr);
-void log_srunner_end (SRunner *sr);
-void log_suite_start (SRunner *sr, Suite *s);
-void log_suite_end (SRunner *sr, Suite *s);
-void log_test_end (SRunner *sr, TestResult *tr);
-void log_test_start (SRunner *sr, TCase *tc, TF *tfun);
+void log_srunner_start (SRunner * sr);
+void log_srunner_end (SRunner * sr);
+void log_suite_start (SRunner * sr, Suite * s);
+void log_suite_end (SRunner * sr, Suite * s);
+void log_test_end (SRunner * sr, TestResult * tr);
+void log_test_start (SRunner * sr, TCase * tc, TF * tfun);
 
-void stdout_lfun (SRunner *sr, FILE *file, enum print_output,
-                 void *obj, enum cl_event evt);
+void stdout_lfun (SRunner * sr, FILE * file, enum print_output,
+    void *obj, enum cl_event evt);
 
-void lfile_lfun (SRunner *sr, FILE *file, enum print_output,
-                 void *obj, enum cl_event evt);
+void lfile_lfun (SRunner * sr, FILE * file, enum print_output,
+    void *obj, enum cl_event evt);
 
-void xml_lfun (SRunner *sr, FILE *file, enum print_output,
-                 void *obj, enum cl_event evt);
+void xml_lfun (SRunner * sr, FILE * file, enum print_output,
+    void *obj, enum cl_event evt);
 
-void subunit_lfun (SRunner *sr, FILE *file, enum print_output,
-                 void *obj, enum cl_event evt);
+void tap_lfun (SRunner * sr, FILE * file, enum print_output,
+    void *obj, enum cl_event evt);
 
-void srunner_register_lfun (SRunner *sr, FILE *lfile, int close,
-                           LFun lfun, enum print_output);
+void subunit_lfun (SRunner * sr, FILE * file, enum print_output,
+    void *obj, enum cl_event evt);
 
-FILE *srunner_open_lfile (SRunner *sr);
-FILE *srunner_open_xmlfile (SRunner *sr);
-void srunner_init_logging (SRunner *sr, enum print_output print_mode);
-void srunner_end_logging (SRunner *sr);
+void srunner_register_lfun (SRunner * sr, FILE * lfile, int close,
+    LFun lfun, enum print_output);
+
+FILE *srunner_open_lfile (SRunner * sr);
+FILE *srunner_open_xmlfile (SRunner * sr);
+FILE *srunner_open_tapfile (SRunner * sr);
+void srunner_init_logging (SRunner * sr, enum print_output print_mode);
+void srunner_end_logging (SRunner * sr);
 
 #endif /* CHECK_LOG_H */
index ae653ff..a55b0b8 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
-#include "config.h"
+#include "../lib/libcompat.h"
 
 #include <sys/types.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
 #include <stdlib.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -34,6 +31,7 @@
 #include "check_impl.h"
 #include "check_msg.h"
 #include "check_pack.h"
+#include "check_str.h"
 
 
 /* 'Pipe' is implemented as a temporary file to overcome message
@@ -57,7 +55,9 @@
  */
 
 static FILE *send_file1;
+static char *send_file1_name;
 static FILE *send_file2;
+static char *send_file2_name;
 
 static FILE *get_pipe (void);
 static void setup_pipe (void);
@@ -86,8 +86,18 @@ send_failure_info (const char *msg)
 {
   FailMsg fmsg;
 
-  fmsg.msg = (char *) msg;
-  ppack (fileno (get_pipe ()), CK_MSG_FAIL, (CheckMsg *) & fmsg);
+  fmsg.msg = strdup (msg);
+  ppack (get_pipe (), CK_MSG_FAIL, (CheckMsg *) & fmsg);
+  free (fmsg.msg);
+}
+
+void
+send_duration_info (int duration)
+{
+  DurationMsg dmsg;
+
+  dmsg.duration = duration;
+  ppack (get_pipe (), CK_MSG_DURATION, (CheckMsg *) & dmsg);
 }
 
 void
@@ -95,9 +105,10 @@ send_loc_info (const char *file, int line)
 {
   LocMsg lmsg;
 
-  lmsg.file = (char *) file;
+  lmsg.file = strdup (file);
   lmsg.line = line;
-  ppack (fileno (get_pipe ()), CK_MSG_LOC, (CheckMsg *) & lmsg);
+  ppack (get_pipe (), CK_MSG_LOC, (CheckMsg *) & lmsg);
+  free (lmsg.file);
 }
 
 void
@@ -106,7 +117,7 @@ send_ctx_info (enum ck_result_ctx ctx)
   CtxMsg cmsg;
 
   cmsg.ctx = ctx;
-  ppack (fileno (get_pipe ()), CK_MSG_CTX, (CheckMsg *) & cmsg);
+  ppack (get_pipe (), CK_MSG_CTX, (CheckMsg *) & cmsg);
 }
 
 TestResult *
@@ -117,10 +128,17 @@ receive_test_result (int waserror)
   TestResult *result;
 
   fp = get_pipe ();
-  if (fp == NULL)
+  if (fp == NULL) {
     eprintf ("Error in call to get_pipe", __FILE__, __LINE__ - 2);
+  }
+
   rewind (fp);
-  rmsg = punpack (fileno (fp));
+  rmsg = punpack (fp);
+
+  if (rmsg == NULL) {
+    eprintf ("Error in call to punpack", __FILE__, __LINE__ - 4);
+  }
+
   teardown_pipe ();
   setup_pipe ();
 
@@ -156,7 +174,7 @@ construct_test_result (RcvMsg * rmsg, int waserror)
   tr = tr_create ();
 
   if (rmsg->msg != NULL || waserror) {
-    tr->ctx = (cur_fork_status () == CK_FORK) ? rmsg->lastctx : rmsg->failctx;
+    tr->ctx = rmsg->lastctx;
     tr->msg = rmsg->msg;
     rmsg->msg = NULL;
     tr_set_loc_by_ctx (tr, tr->ctx, rmsg);
@@ -167,6 +185,7 @@ construct_test_result (RcvMsg * rmsg, int waserror)
   } else {
     tr->ctx = CK_CTX_TEST;
     tr->msg = NULL;
+    tr->duration = rmsg->duration;
     tr_set_loc_by_ctx (tr, CK_CTX_TEST, rmsg);
   }
 
@@ -185,16 +204,67 @@ teardown_messaging (void)
   teardown_pipe ();
 }
 
+/**
+ * Open a temporary file.
+ *
+ * If the file could be unlinked upon creation, the name
+ * of the file is not returned via 'name'. However, if the
+ * file could not be unlinked, the name is returned,
+ * expecting the caller to both delete the file and
+ * free the 'name' field after the file is closed.
+ */
+FILE *
+open_tmp_file (char **name)
+{
+  FILE *file;
+
+  *name = NULL;
+
+  /* Windows does not like tmpfile(). This is likely because tmpfile()
+   * call unlink() on the file before returning it, to make sure the
+   * file is deleted when it is closed. The unlink() call also fails
+   * on Windows if the file is still open. */
+  /* also note that mkstemp is apparently a C90 replacement for tmpfile */
+  /* perhaps all we need to do on Windows is set TMPDIR to whatever is
+     stored in TEMP for tmpfile to work */
+  /* and finally, the "b" from "w+b" is ignored on OS X, not sure about WIN32 */
+
+  file = tmpfile ();
+  if (file == NULL) {
+    char *tmp = getenv ("TEMP");
+    char *tmp_file = tempnam (tmp, "check_");
+
+    /*
+     * Note, tempnam is not enough to get a unique name. Between
+     * getting the name and opening the file, something else also
+     * calling tempnam() could get the same name. It has been observed
+     * on MinGW-w64 builds on Wine that this exact thing happens
+     * if multiple instances of a unit tests are running concurrently.
+     * To prevent two concurrent unit tests from getting the same file,
+     * we append the pid to the file. The pid should be unique on the
+     * system.
+     */
+    char *uniq_tmp_file = ck_strdup_printf ("%s.%d", tmp_file, getpid ());
+
+    file = fopen (uniq_tmp_file, "w+b");
+    *name = uniq_tmp_file;
+    free (tmp_file);
+  }
+  return file;
+}
+
 static void
 setup_pipe (void)
 {
-  if (send_file1 != 0) {
-    if (send_file2 != 0)
-      eprintf ("Only one nesting of suite runs supported", __FILE__, __LINE__);
-    send_file2 = tmpfile ();
-  } else {
-    send_file1 = tmpfile ();
+  if (send_file1 == NULL) {
+    send_file1 = open_tmp_file (&send_file1_name);
+    return;
+  }
+  if (send_file2 == NULL) {
+    send_file2 = open_tmp_file (&send_file2_name);
+    return;
   }
+  eprintf ("Only one nesting of suite runs supported", __FILE__, __LINE__);
 }
 
 static void
@@ -203,9 +273,19 @@ teardown_pipe (void)
   if (send_file2 != 0) {
     fclose (send_file2);
     send_file2 = 0;
+    if (send_file2_name != NULL) {
+      unlink (send_file2_name);
+      free (send_file2_name);
+      send_file2_name = NULL;
+    }
   } else if (send_file1 != 0) {
     fclose (send_file1);
     send_file1 = 0;
+    if (send_file1_name != NULL) {
+      unlink (send_file1_name);
+      free (send_file1_name);
+      send_file1_name = NULL;
+    }
   } else {
     eprintf ("No messaging setup", __FILE__, __LINE__);
   }
index 6ddaa3d..f84ee8c 100644 (file)
 
 /* Functions implementing messaging during test runs */
 
-void send_failure_info(const char *msg);
-void send_loc_info(const char *file, int line);
-void send_ctx_info(enum ck_result_ctx ctx);
+void send_failure_info (const char *msg);
+void send_loc_info (const char *file, int line);
+void send_ctx_info (enum ck_result_ctx ctx);
+void send_duration_info (int duration);
 
-TestResult *receive_test_result(int waserror);
+TestResult *receive_test_result (int waserror);
 
-void setup_messaging(void);
-void teardown_messaging(void);
+void setup_messaging (void);
+void teardown_messaging (void);
+
+FILE *open_tmp_file (char **name);
 
 #endif /*CHECK_MSG_NEW_H */
index c34644a..a3f635d 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
-#include "config.h"
+#include "../lib/libcompat.h"
 
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "_stdint.h"
-
 #include "check.h"
 #include "check_error.h"
 #include "check_list.h"
 #include "check_impl.h"
 #include "check_pack.h"
 
-#ifdef HAVE_PTHREAD
-#include <pthread.h>
-pthread_mutex_t lock_mutex = PTHREAD_MUTEX_INITIALIZER;
-#else
+#ifndef HAVE_PTHREAD
 #define pthread_mutex_lock(arg)
 #define pthread_mutex_unlock(arg)
+#define pthread_cleanup_push(f,a) {
+#define pthread_cleanup_pop(e) }
 #endif
 
+/* Maximum size for one message in the message stream. */
+#define CK_MAX_MSG_SIZE 8192
+/* This is used to implement a sliding window on the receiving
+ * side. When sending messages, we assure that no single message
+ * is bigger than this (actually we check against CK_MAX_MSG_SIZE/2).
+ * The usual size for a message is less than 80 bytes.
+ * All this is done instead of the previous approach to allocate (actually
+ * continuously reallocate) one big chunk for the whole message stream.
+ * Problems were seen in the wild with up to 4 GB reallocations.
+ */
+
+
 /* typedef an unsigned int that has at least 4 bytes */
 typedef uint32_t ck_uint32;
 
@@ -56,15 +61,17 @@ static char *upack_str (char **buf);
 static int pack_ctx (char **buf, CtxMsg * cmsg);
 static int pack_loc (char **buf, LocMsg * lmsg);
 static int pack_fail (char **buf, FailMsg * fmsg);
+static int pack_duration (char **buf, DurationMsg * fmsg);
 static void upack_ctx (char **buf, CtxMsg * cmsg);
 static void upack_loc (char **buf, LocMsg * lmsg);
 static void upack_fail (char **buf, FailMsg * fmsg);
+static void upack_duration (char **buf, DurationMsg * fmsg);
 
 static void check_type (int type, const char *file, int line);
 static enum ck_msg_type upack_type (char **buf);
 static void pack_type (char **buf, enum ck_msg_type type);
 
-static int read_buf (int fdes, char **buf);
+static int read_buf (FILE * fdes, int size, char *buf);
 static int get_result (char *buf, RcvMsg * rmsg);
 static void rcvmsg_update_ctx (RcvMsg * rmsg, enum ck_result_ctx ctx);
 static void rcvmsg_update_loc (RcvMsg * rmsg, const char *file, int line);
@@ -77,13 +84,15 @@ typedef void (*upfun) (char **, CheckMsg *);
 static pfun pftab[] = {
   (pfun) pack_ctx,
   (pfun) pack_fail,
-  (pfun) pack_loc
+  (pfun) pack_loc,
+  (pfun) pack_duration
 };
 
 static upfun upftab[] = {
   (upfun) upack_ctx,
   (upfun) upack_fail,
-  (upfun) upack_loc
+  (upfun) upack_loc,
+  (upfun) upack_duration
 };
 
 int
@@ -103,7 +112,6 @@ int
 upack (char *buf, CheckMsg * msg, enum ck_msg_type *type)
 {
   char *obuf;
-  int nread;
 
   if (buf == NULL)
     return -1;
@@ -116,8 +124,7 @@ upack (char *buf, CheckMsg * msg, enum ck_msg_type *type)
 
   upftab[*type] (&buf, msg);
 
-  nread = buf - obuf;
-  return nread;
+  return buf - obuf;
 }
 
 static void
@@ -126,10 +133,10 @@ pack_int (char **buf, int val)
   unsigned char *ubuf = (unsigned char *) *buf;
   ck_uint32 uval = val;
 
-  ubuf[0] = (uval >> 24) & 0xFF;
-  ubuf[1] = (uval >> 16) & 0xFF;
-  ubuf[2] = (uval >> 8) & 0xFF;
-  ubuf[3] = uval & 0xFF;
+  ubuf[0] = (unsigned char) ((uval >> 24) & 0xFF);
+  ubuf[1] = (unsigned char) ((uval >> 16) & 0xFF);
+  ubuf[2] = (unsigned char) ((uval >> 8) & 0xFF);
+  ubuf[3] = (unsigned char) (uval & 0xFF);
 
   *buf += 4;
 }
@@ -140,7 +147,9 @@ upack_int (char **buf)
   unsigned char *ubuf = (unsigned char *) *buf;
   ck_uint32 uval;
 
-  uval = ((ubuf[0] << 24) | (ubuf[1] << 16) | (ubuf[2] << 8) | ubuf[3]);
+  uval =
+      (ck_uint32) ((ubuf[0] << 24) | (ubuf[1] << 16) | (ubuf[2] << 8) |
+      ubuf[3]);
 
   *buf += 4;
 
@@ -174,12 +183,12 @@ upack_str (char **buf)
   strsz = upack_int (buf);
 
   if (strsz > 0) {
-    val = emalloc (strsz + 1);
+    val = (char *) emalloc (strsz + 1);
     memcpy (val, *buf, strsz);
     val[strsz] = 0;
     *buf += strsz;
   } else {
-    val = emalloc (1);
+    val = (char *) emalloc (1);
     *val = 0;
   }
 
@@ -206,7 +215,7 @@ pack_ctx (char **buf, CtxMsg * cmsg)
   int len;
 
   len = 4 + 4;
-  *buf = ptr = emalloc (len);
+  *buf = ptr = (char *) emalloc (len);
 
   pack_type (&ptr, CK_MSG_CTX);
   pack_int (&ptr, (int) cmsg->ctx);
@@ -217,7 +226,28 @@ pack_ctx (char **buf, CtxMsg * cmsg)
 static void
 upack_ctx (char **buf, CtxMsg * cmsg)
 {
-  cmsg->ctx = upack_int (buf);
+  cmsg->ctx = (enum ck_result_ctx) upack_int (buf);
+}
+
+static int
+pack_duration (char **buf, DurationMsg * cmsg)
+{
+  char *ptr;
+  int len;
+
+  len = 4 + 4;
+  *buf = ptr = (char *) emalloc (len);
+
+  pack_type (&ptr, CK_MSG_DURATION);
+  pack_int (&ptr, cmsg->duration);
+
+  return len;
+}
+
+static void
+upack_duration (char **buf, DurationMsg * cmsg)
+{
+  cmsg->duration = upack_int (buf);
 }
 
 static int
@@ -227,7 +257,7 @@ pack_loc (char **buf, LocMsg * lmsg)
   int len;
 
   len = 4 + 4 + (lmsg->file ? strlen (lmsg->file) : 0) + 4;
-  *buf = ptr = emalloc (len);
+  *buf = ptr = (char *) emalloc (len);
 
   pack_type (&ptr, CK_MSG_LOC);
   pack_str (&ptr, lmsg->file);
@@ -250,7 +280,7 @@ pack_fail (char **buf, FailMsg * fmsg)
   int len;
 
   len = 4 + 4 + (fmsg->msg ? strlen (fmsg->msg) : 0);
-  *buf = ptr = emalloc (len);
+  *buf = ptr = (char *) emalloc (len);
 
   pack_type (&ptr, CK_MSG_FAIL);
   pack_str (&ptr, fmsg->msg);
@@ -272,54 +302,52 @@ check_type (int type, const char *file, int line)
 }
 
 #ifdef HAVE_PTHREAD
-pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t ck_mutex_lock = PTHREAD_MUTEX_INITIALIZER;
+static void
+ppack_cleanup (void *mutex)
+{
+  pthread_mutex_unlock ((pthread_mutex_t *) mutex);
+}
 #endif
 
 void
-ppack (int fdes, enum ck_msg_type type, CheckMsg * msg)
+ppack (FILE * fdes, enum ck_msg_type type, CheckMsg * msg)
 {
-  char *buf;
+  char *buf = NULL;
   int n;
   ssize_t r;
 
   n = pack (type, &buf, msg);
-  pthread_mutex_lock (&mutex_lock);
-  r = write (fdes, buf, n);
-  pthread_mutex_unlock (&mutex_lock);
-  if (r == -1)
-    eprintf ("Error in call to write:", __FILE__, __LINE__ - 2);
+  /* Keep it on the safe side to not send too much data. */
+  if (n > (CK_MAX_MSG_SIZE / 2))
+    eprintf ("Message string too long", __FILE__, __LINE__ - 2);
+
+  pthread_cleanup_push (ppack_cleanup, &ck_mutex_lock);
+  pthread_mutex_lock (&ck_mutex_lock);
+  r = fwrite (buf, 1, n, fdes);
+  fflush (fdes);
+  pthread_mutex_unlock (&ck_mutex_lock);
+  pthread_cleanup_pop (0);
+  if (r != n)
+    eprintf ("Error in call to fwrite:", __FILE__, __LINE__ - 2);
 
   free (buf);
 }
 
 static int
-read_buf (int fdes, char **buf)
+read_buf (FILE * fdes, int size, char *buf)
 {
-  char *readloc;
   int n;
-  int nread = 0;
-  int size = 1;
-  int grow = 2;
-
-  *buf = emalloc (size);
-  readloc = *buf;
-  while (1) {
-    n = read (fdes, readloc, size - nread);
-    if (n == 0)
-      break;
-    if (n == -1)
-      eprintf ("Error in call to read:", __FILE__, __LINE__ - 4);
-
-    nread += n;
-    size *= grow;
-    *buf = erealloc (*buf, size);
-    readloc = *buf + nread;
+
+  n = fread (buf, 1, size, fdes);
+
+  if (ferror (fdes)) {
+    eprintf ("Error in call to fread:", __FILE__, __LINE__ - 4);
   }
 
-  return nread;
+  return n;
 }
 
-
 static int
 get_result (char *buf, RcvMsg * rmsg)
 {
@@ -333,23 +361,29 @@ get_result (char *buf, RcvMsg * rmsg)
 
   if (type == CK_MSG_CTX) {
     CtxMsg *cmsg = (CtxMsg *) & msg;
+
     rcvmsg_update_ctx (rmsg, cmsg->ctx);
   } else if (type == CK_MSG_LOC) {
     LocMsg *lmsg = (LocMsg *) & msg;
+
     if (rmsg->failctx == CK_CTX_INVALID) {
       rcvmsg_update_loc (rmsg, lmsg->file, lmsg->line);
     }
     free (lmsg->file);
   } else if (type == CK_MSG_FAIL) {
     FailMsg *fmsg = (FailMsg *) & msg;
+
     if (rmsg->msg == NULL) {
-      rmsg->msg = emalloc (strlen (fmsg->msg) + 1);
-      strcpy (rmsg->msg, fmsg->msg);
+      rmsg->msg = strdup (fmsg->msg);
       rmsg->failctx = rmsg->lastctx;
     } else {
       /* Skip subsequent failure messages, only happens for CK_NOFORK */
     }
     free (fmsg->msg);
+  } else if (type == CK_MSG_DURATION) {
+    DurationMsg *cmsg = (DurationMsg *) & msg;
+
+    rmsg->duration = cmsg->duration;
   } else
     check_type (type, __FILE__, __LINE__);
 
@@ -375,10 +409,11 @@ rcvmsg_create (void)
 {
   RcvMsg *rmsg;
 
-  rmsg = emalloc (sizeof (RcvMsg));
+  rmsg = (RcvMsg *) emalloc (sizeof (RcvMsg));
   rmsg->lastctx = CK_CTX_INVALID;
   rmsg->failctx = CK_CTX_INVALID;
   rmsg->msg = NULL;
+  rmsg->duration = -1;
   reset_rcv_test (rmsg);
   reset_rcv_fixture (rmsg);
   return rmsg;
@@ -406,40 +441,47 @@ rcvmsg_update_ctx (RcvMsg * rmsg, enum ck_result_ctx ctx)
 static void
 rcvmsg_update_loc (RcvMsg * rmsg, const char *file, int line)
 {
-  int flen = strlen (file);
-
   if (rmsg->lastctx == CK_CTX_TEST) {
     free (rmsg->test_file);
     rmsg->test_line = line;
-    rmsg->test_file = emalloc (flen + 1);
-    strcpy (rmsg->test_file, file);
+    rmsg->test_file = strdup (file);
   } else {
     free (rmsg->fixture_file);
     rmsg->fixture_line = line;
-    rmsg->fixture_file = emalloc (flen + 1);
-    strcpy (rmsg->fixture_file, file);
+    rmsg->fixture_file = strdup (file);
   }
 }
 
 RcvMsg *
-punpack (int fdes)
+punpack (FILE * fdes)
 {
-  int nread, n;
+  int nread, nparse, n;
   char *buf;
-  char *obuf;
   RcvMsg *rmsg;
 
-  nread = read_buf (fdes, &buf);
-  obuf = buf;
   rmsg = rcvmsg_create ();
 
-  while (nread > 0) {
+  /* Allcate a buffer */
+  buf = (char *) emalloc (CK_MAX_MSG_SIZE);
+  /* Fill the buffer from the file */
+  nread = read_buf (fdes, CK_MAX_MSG_SIZE, buf);
+  nparse = nread;
+  /* While not all parsed */
+  while (nparse > 0) {
+    /* Parse one message */
     n = get_result (buf, rmsg);
-    nread -= n;
-    buf += n;
+    nparse -= n;
+    /* Move remaining data in buffer to the beginning */
+    memmove (buf, buf + n, nparse);
+    /* If EOF has not been seen */
+    if (nread > 0) {
+      /* Read more data into empty space at end of the buffer */
+      nread = read_buf (fdes, n, buf + nparse);
+      nparse += nread;
+    }
   }
+  free (buf);
 
-  free (obuf);
   if (rmsg->lastctx == CK_CTX_INVALID) {
     free (rmsg);
     rmsg = NULL;
index 3b916c9..7bde267 100644 (file)
 #define CHECK_PACK_H
 
 
-enum ck_msg_type {
+enum ck_msg_type
+{
   CK_MSG_CTX,
   CK_MSG_FAIL,
   CK_MSG_LOC,
+  CK_MSG_DURATION,
   CK_MSG_LAST
 };
 
@@ -34,7 +36,7 @@ typedef struct CtxMsg
   enum ck_result_ctx ctx;
 } CtxMsg;
 
-typedef struct LocMsg 
+typedef struct LocMsg
 {
   int line;
   char *file;
@@ -45,11 +47,17 @@ typedef struct FailMsg
   char *msg;
 } FailMsg;
 
+typedef struct DurationMsg
+{
+  int duration;
+} DurationMsg;
+
 typedef union
 {
-  CtxMsg  ctx_msg;
+  CtxMsg ctx_msg;
   FailMsg fail_msg;
-  LocMsg  loc_msg;
+  LocMsg loc_msg;
+  DurationMsg duration_msg;
 } CheckMsg;
 
 typedef struct RcvMsg
@@ -61,16 +69,16 @@ typedef struct RcvMsg
   char *test_file;
   int test_line;
   char *msg;
+  int duration;
 } RcvMsg;
 
-void rcvmsg_free (RcvMsg *rmsg);
+void rcvmsg_free (RcvMsg * rmsg);
 
-  
-int pack (enum ck_msg_type type, char **buf, CheckMsg *msg);
-int upack (char *buf, CheckMsg *msg, enum ck_msg_type *type);
 
-void ppack (int fdes, enum ck_msg_type type, CheckMsg *msg);
-RcvMsg *punpack (int fdes);
+int pack (enum ck_msg_type type, char **buf, CheckMsg * msg);
+int upack (char *buf, CheckMsg * msg, enum ck_msg_type *type);
 
+void ppack (FILE * fdes, enum ck_msg_type type, CheckMsg * msg);
+RcvMsg *punpack (FILE * fdes);
 
 #endif /*CHECK_PACK_H */
index e29aa7b..c84e158 100644 (file)
@@ -18,7 +18,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#include "config.h"
+#include "../lib/libcompat.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -83,30 +83,16 @@ srunner_fprint_results (FILE * file, SRunner * sr, enum print_output print_mode)
 
   resultlst = sr->resultlst;
 
-  for (list_front (resultlst); !list_at_end (resultlst);
-      list_advance (resultlst)) {
-    TestResult *tr = list_val (resultlst);
+  for (check_list_front (resultlst); !check_list_at_end (resultlst);
+      check_list_advance (resultlst)) {
+    TestResult *tr = (TestResult *) check_list_val (resultlst);
+
     tr_fprint (file, tr, print_mode);
   }
   return;
 }
 
 void
-tr_fprint (FILE * file, TestResult * tr, enum print_output print_mode)
-{
-  if (print_mode == CK_ENV) {
-    print_mode = get_env_printmode ();
-  }
-
-  if ((print_mode >= CK_VERBOSE && tr->rtype == CK_PASS) ||
-      (tr->rtype != CK_PASS && print_mode >= CK_NORMAL)) {
-    char *trstr = tr_str (tr);
-    fprintf (file, "%s\n", trstr);
-    free (trstr);
-  }
-}
-
-static void
 fprint_xml_esc (FILE * file, const char *str)
 {
   for (; *str != '\0'; str++) {
@@ -139,23 +125,39 @@ fprint_xml_esc (FILE * file, const char *str)
 }
 
 void
+tr_fprint (FILE * file, TestResult * tr, enum print_output print_mode)
+{
+  if (print_mode == CK_ENV) {
+    print_mode = get_env_printmode ();
+  }
+
+  if ((print_mode >= CK_VERBOSE && tr->rtype == CK_PASS) ||
+      (tr->rtype != CK_PASS && print_mode >= CK_NORMAL)) {
+    char *trstr = tr_str (tr);
+
+    fprintf (file, "%s\n", trstr);
+    free (trstr);
+  }
+}
+
+void
 tr_xmlprint (FILE * file, TestResult * tr,
     enum print_output print_mode CK_ATTRIBUTE_UNUSED)
 {
   char result[10];
-  char *path_name;
-  char *file_name;
-  char *slash;
+  char *path_name = NULL;
+  char *file_name = NULL;
+  char *slash = NULL;
 
   switch (tr->rtype) {
     case CK_PASS:
-      strcpy (result, "success");
+      snprintf (result, sizeof (result), "%s", "success");
       break;
     case CK_FAILURE:
-      strcpy (result, "failure");
+      snprintf (result, sizeof (result), "%s", "failure");
       break;
     case CK_ERROR:
-      strcpy (result, "error");
+      snprintf (result, sizeof (result), "%s", "error");
       break;
     case CK_TEST_RESULT_INVALID:
     default:
@@ -163,22 +165,33 @@ tr_xmlprint (FILE * file, TestResult * tr,
       break;
   }
 
-  slash = strrchr (tr->file, '/');
-  if (slash == NULL) {
-    path_name = (char *) ".";
-    file_name = tr->file;
-  } else {
-    path_name = strdup (tr->file);
-    path_name[slash - tr->file] = 0;    /* Terminate the temporary string. */
-    file_name = slash + 1;
+  if (tr->file) {
+    slash = strrchr (tr->file, '/');
+    if (slash == NULL) {
+      slash = strrchr (tr->file, '\\');
+    }
+
+    if (slash == NULL) {
+      path_name = strdup (".");
+      file_name = tr->file;
+    } else {
+      path_name = strdup (tr->file);
+      path_name[slash - tr->file] = 0;  /* Terminate the temporary string. */
+      file_name = slash + 1;
+    }
   }
 
 
   fprintf (file, "    <test result=\"%s\">\n", result);
-  fprintf (file, "      <path>%s</path>\n", path_name);
-  fprintf (file, "      <fn>%s:%d</fn>\n", file_name, tr->line);
+  fprintf (file, "      <path>%s</path>\n",
+      (path_name == NULL ? "" : path_name));
+  fprintf (file, "      <fn>%s:%d</fn>\n",
+      (file_name == NULL ? "" : file_name), tr->line);
   fprintf (file, "      <id>%s</id>\n", tr->tname);
   fprintf (file, "      <iteration>%d</iteration>\n", tr->iter);
+  fprintf (file, "      <duration>%d.%06d</duration>\n",
+      tr->duration < 0 ? -1 : tr->duration / US_PER_SEC,
+      tr->duration < 0 ? 0 : tr->duration % US_PER_SEC);
   fprintf (file, "      <description>");
   fprint_xml_esc (file, tr->tcname);
   fprintf (file, "</description>\n");
@@ -187,15 +200,14 @@ tr_xmlprint (FILE * file, TestResult * tr,
   fprintf (file, "</message>\n");
   fprintf (file, "    </test>\n");
 
-  if (slash != NULL) {
-    free (path_name);
-  }
+  free (path_name);
 }
 
 enum print_output
 get_env_printmode (void)
 {
   char *env = getenv ("CK_VERBOSITY");
+
   if (env == NULL)
     return CK_NORMAL;
   if (strcmp (env, "silent") == 0)
index 18c0f62..f75274b 100644 (file)
 #ifndef CHECK_PRINT_H
 #define CHECK_PRINT_H
 
-void tr_fprint (FILE *file, TestResult *tr, enum print_output print_mode);
-void tr_xmlprint (FILE *file, TestResult *tr, enum print_output print_mode);
-void srunner_fprint (FILE *file, SRunner *sr, enum print_output print_mode);
+/* escape XML special characters (" ' < > &) in str and print to file */
+void fprint_xml_esc (FILE * file, const char *str);
+void tr_fprint (FILE * file, TestResult * tr, enum print_output print_mode);
+void tr_xmlprint (FILE * file, TestResult * tr, enum print_output print_mode);
+void srunner_fprint (FILE * file, SRunner * sr, enum print_output print_mode);
 enum print_output get_env_printmode (void);
 
 
index 0c7b815..bd0f637 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
-#include "config.h"
+#include "../lib/libcompat.h"
 
 #include <sys/types.h>
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
+#include <time.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
 #include <signal.h>
+#include <setjmp.h>
 
 #include "check.h"
 #include "check_error.h"
@@ -56,35 +52,40 @@ enum tf_type
   CK_NOFORK_FIXTURE
 };
 
+
 /* all functions are defined in the same order they are declared.
    functions that depend on forking are gathered all together.
    non-static functions are at the end of the file. */
 static void srunner_run_init (SRunner * sr, enum print_output print_mode);
 static void srunner_run_end (SRunner * sr, enum print_output print_mode);
-static void srunner_iterate_suites (SRunner * sr, enum print_output print_mode);
+static void srunner_iterate_suites (SRunner * sr,
+    const char *sname, const char *tcname, enum print_output print_mode);
 static void srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc);
 static void srunner_add_failure (SRunner * sr, TestResult * tf);
+static TestResult *srunner_run_setup (List * func_list,
+    enum fork_status fork_usage, const char *test_name, const char *setup_name);
 static int srunner_run_unchecked_setup (SRunner * sr, TCase * tc);
 static TestResult *tcase_run_checked_setup (SRunner * sr, TCase * tc);
-static void srunner_run_teardown (List * l);
-static void srunner_run_unchecked_teardown (TCase * tc);
+static void srunner_run_teardown (List * fixture_list,
+    enum fork_status fork_usage);
+static void srunner_run_unchecked_teardown (SRunner * sr, TCase * tc);
 static void tcase_run_checked_teardown (TCase * tc);
 static void srunner_run_tcase (SRunner * sr, TCase * tc);
 static TestResult *tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tf,
     int i);
 static TestResult *receive_result_info_nofork (const char *tcname,
-    const char *tname, int iter);
+    const char *tname, int iter, int duration);
 static void set_nofork_info (TestResult * tr);
 static char *pass_msg (void);
 
-#ifdef _POSIX_VERSION
+#if defined(HAVE_FORK) && HAVE_FORK==1
 static TestResult *tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tf,
     int i);
 static TestResult *receive_result_info_fork (const char *tcname,
-    const char *tname, int iter, int status, int expected_signal,
-    unsigned char allowed_exit_value);
+    const char *tname, int iter,
+    int status, int expected_signal, signed char allowed_exit_value);
 static void set_fork_info (TestResult * tr, int status, int expected_signal,
-    unsigned char allowed_exit_value);
+    signed char allowed_exit_value);
 static char *signal_msg (int sig);
 static char *signal_error_msg (int signal_received, int signal_expected);
 static char *exit_msg (int exitstatus);
@@ -106,7 +107,7 @@ sig_handler (int sig_nr)
       break;
   }
 }
-#endif /* _POSIX_VERSION */
+#endif /* HAVE_FORK */
 
 #define MSG_LEN 100
 
@@ -130,6 +131,7 @@ srunner_run_end (SRunner * sr, enum print_output CK_ATTRIBUTE_UNUSED print_mode)
 
 static void
 srunner_iterate_suites (SRunner * sr,
+    const char *sname, const char *tcname,
     enum print_output CK_ATTRIBUTE_UNUSED print_mode)
 {
   List *slst;
@@ -138,15 +140,26 @@ srunner_iterate_suites (SRunner * sr,
 
   slst = sr->slst;
 
-  for (list_front (slst); !list_at_end (slst); list_advance (slst)) {
-    Suite *s = list_val (slst);
+  for (check_list_front (slst); !check_list_at_end (slst);
+      check_list_advance (slst)) {
+    Suite *s = (Suite *) check_list_val (slst);
+
+    if (((sname != NULL) && (strcmp (sname, s->name) != 0))
+        || ((tcname != NULL) && (!suite_tcase (s, tcname))))
+      continue;
 
     log_suite_start (sr, s);
 
     tcl = s->tclst;
 
-    for (list_front (tcl); !list_at_end (tcl); list_advance (tcl)) {
-      tc = list_val (tcl);
+    for (check_list_front (tcl); !check_list_at_end (tcl);
+        check_list_advance (tcl)) {
+      tc = (TCase *) check_list_val (tcl);
+
+      if ((tcname != NULL) && (strcmp (tcname, tc->name) != 0)) {
+        continue;
+      }
+
       srunner_run_tcase (sr, tc);
     }
 
@@ -163,28 +176,34 @@ srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc)
 
   tfl = tc->tflst;
 
-  for (list_front (tfl); !list_at_end (tfl); list_advance (tfl)) {
+  for (check_list_front (tfl); !check_list_at_end (tfl);
+      check_list_advance (tfl)) {
     int i;
-    tfun = list_val (tfl);
+
+    tfun = (TF *) check_list_val (tfl);
 
     for (i = tfun->loop_start; i < tfun->loop_end; i++) {
       log_test_start (sr, tc, tfun);
       switch (srunner_fork_status (sr)) {
         case CK_FORK:
-#ifdef _POSIX_VERSION
+#if defined(HAVE_FORK) && HAVE_FORK==1
           tr = tcase_run_tfun_fork (sr, tc, tfun, i);
-#else /* _POSIX_VERSION */
+#else /* HAVE_FORK */
           eprintf ("This version does not support fork", __FILE__, __LINE__);
-#endif /* _POSIX_VERSION */
+#endif /* HAVE_FORK */
           break;
         case CK_NOFORK:
           tr = tcase_run_tfun_nofork (sr, tc, tfun, i);
           break;
+        case CK_FORK_GETENV:
         default:
           eprintf ("Bad fork status in SRunner", __FILE__, __LINE__);
       }
-      srunner_add_failure (sr, tr);
-      log_test_end (sr, tr);
+
+      if (NULL != tr) {
+        srunner_add_failure (sr, tr);
+        log_test_end (sr, tr);
+      }
     }
   }
 }
@@ -192,7 +211,7 @@ srunner_iterate_tcase_tfuns (SRunner * sr, TCase * tc)
 static void
 srunner_add_failure (SRunner * sr, TestResult * tr)
 {
-  list_add_end (sr->resultlst, tr);
+  check_list_add_end (sr->resultlst, tr);
   sr->stats->n_checked++;       /* count checks during setup, test, and teardown */
   if (tr->rtype == CK_FAILURE)
     sr->stats->n_failed++;
@@ -201,62 +220,30 @@ srunner_add_failure (SRunner * sr, TestResult * tr)
 
 }
 
-static int
-srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
-{
-  TestResult *tr;
-  List *l;
-  Fixture *f;
-  int rval = 1;
-
-  set_fork_status (CK_NOFORK);
-
-  l = tc->unch_sflst;
-
-  for (list_front (l); !list_at_end (l); list_advance (l)) {
-    send_ctx_info (CK_CTX_SETUP);
-    f = list_val (l);
-    f->fun ();
-
-    tr = receive_result_info_nofork (tc->name, "unchecked_setup", 0);
-
-    if (tr->rtype != CK_PASS) {
-      srunner_add_failure (sr, tr);
-      rval = 0;
-      break;
-    }
-    free (tr->file);
-    free (tr->msg);
-    free (tr);
-  }
-
-  set_fork_status (srunner_fork_status (sr));
-  return rval;
-}
-
 static TestResult *
-tcase_run_checked_setup (SRunner * sr, TCase * tc)
+srunner_run_setup (List * fixture_list, enum fork_status fork_usage,
+    const char *test_name, const char *setup_name)
 {
   TestResult *tr = NULL;
-  List *l;
-  Fixture *f;
-  enum fork_status fstat = srunner_fork_status (sr);
+  Fixture *setup_fixture;
 
-  l = tc->ch_sflst;
-  if (fstat == CK_FORK) {
+  if (fork_usage == CK_FORK) {
     send_ctx_info (CK_CTX_SETUP);
   }
 
-  for (list_front (l); !list_at_end (l); list_advance (l)) {
-    if (fstat == CK_NOFORK) {
+  for (check_list_front (fixture_list); !check_list_at_end (fixture_list);
+      check_list_advance (fixture_list)) {
+    setup_fixture = (Fixture *) check_list_val (fixture_list);
+
+    if (fork_usage == CK_NOFORK) {
       send_ctx_info (CK_CTX_SETUP);
-    }
-    f = list_val (l);
-    f->fun ();
 
-    /* Stop the setup and return the failure if nofork mode. */
-    if (fstat == CK_NOFORK) {
-      tr = receive_result_info_nofork (tc->name, "checked_setup", 0);
+      if (0 == setjmp (error_jmp_buffer)) {
+        setup_fixture->fun ();
+      }
+
+      /* Stop the setup and return the failure in nofork mode. */
+      tr = receive_result_info_nofork (test_name, setup_name, 0, -1);
       if (tr->rtype != CK_PASS) {
         break;
       }
@@ -265,34 +252,75 @@ tcase_run_checked_setup (SRunner * sr, TCase * tc)
       free (tr->msg);
       free (tr);
       tr = NULL;
+    } else {
+      setup_fixture->fun ();
     }
   }
 
   return tr;
 }
 
+static int
+srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
+{
+  TestResult *tr = NULL;
+  int rval = 1;
+
+  set_fork_status (CK_NOFORK);
+  tr = srunner_run_setup (tc->unch_sflst, CK_NOFORK, tc->name,
+      "unchecked_setup");
+  set_fork_status (srunner_fork_status (sr));
+
+  if (tr != NULL && tr->rtype != CK_PASS) {
+    srunner_add_failure (sr, tr);
+    rval = 0;
+  }
+
+  return rval;
+}
+
+static TestResult *
+tcase_run_checked_setup (SRunner * sr, TCase * tc)
+{
+  TestResult *tr = srunner_run_setup (tc->ch_sflst, srunner_fork_status (sr),
+      tc->name, "checked_setup");
+
+  return tr;
+}
+
 static void
-srunner_run_teardown (List * l)
+srunner_run_teardown (List * fixture_list, enum fork_status fork_usage)
 {
-  Fixture *f;
+  Fixture *fixture;
 
-  for (list_front (l); !list_at_end (l); list_advance (l)) {
-    f = list_val (l);
+  for (check_list_front (fixture_list); !check_list_at_end (fixture_list);
+      check_list_advance (fixture_list)) {
+    fixture = (Fixture *) check_list_val (fixture_list);
     send_ctx_info (CK_CTX_TEARDOWN);
-    f->fun ();
+
+    if (fork_usage == CK_NOFORK) {
+      if (0 == setjmp (error_jmp_buffer)) {
+        fixture->fun ();
+      } else {
+        /* Abort the remaining teardowns */
+        break;
+      }
+    } else {
+      fixture->fun ();
+    }
   }
 }
 
 static void
-srunner_run_unchecked_teardown (TCase * tc)
+srunner_run_unchecked_teardown (SRunner * sr, TCase * tc)
 {
-  srunner_run_teardown (tc->unch_tflst);
+  srunner_run_teardown (tc->unch_tflst, srunner_fork_status (sr));
 }
 
 static void
 tcase_run_checked_teardown (TCase * tc)
 {
-  srunner_run_teardown (tc->ch_tflst);
+  srunner_run_teardown (tc->ch_tflst, CK_NOFORK);
 }
 
 static void
@@ -300,7 +328,7 @@ srunner_run_tcase (SRunner * sr, TCase * tc)
 {
   if (srunner_run_unchecked_setup (sr, tc)) {
     srunner_iterate_tcase_tfuns (sr, tc);
-    srunner_run_unchecked_teardown (tc);
+    srunner_run_unchecked_teardown (sr, tc);
   }
 }
 
@@ -308,29 +336,40 @@ static TestResult *
 tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tfun, int i)
 {
   TestResult *tr;
+  struct timespec ts_start = { 0, 0 }, ts_end = {
+  0, 0};
 
   tr = tcase_run_checked_setup (sr, tc);
   if (tr == NULL) {
-    tfun->fn (i);
+    clock_gettime (check_get_clockid (), &ts_start);
+    if (0 == setjmp (error_jmp_buffer)) {
+      tfun->fn (i);
+    }
+    clock_gettime (check_get_clockid (), &ts_end);
     tcase_run_checked_teardown (tc);
-    return receive_result_info_nofork (tc->name, tfun->name, i);
+    return receive_result_info_nofork (tc->name, tfun->name, i,
+        DIFF_IN_USEC (ts_start, ts_end));
   }
 
   return tr;
 }
 
 static TestResult *
-receive_result_info_nofork (const char *tcname, const char *tname, int iter)
+receive_result_info_nofork (const char *tcname,
+    const char *tname, int iter, int duration)
 {
   TestResult *tr;
 
   tr = receive_test_result (0);
-  if (tr == NULL)
+  if (tr == NULL) {
     eprintf ("Failed to receive test result", __FILE__, __LINE__);
-  tr->tcname = tcname;
-  tr->tname = tname;
-  tr->iter = iter;
-  set_nofork_info (tr);
+  } else {
+    tr->tcname = tcname;
+    tr->tname = tname;
+    tr->iter = iter;
+    tr->duration = duration;
+    set_nofork_info (tr);
+  }
 
   return tr;
 }
@@ -349,18 +388,23 @@ set_nofork_info (TestResult * tr)
 static char *
 pass_msg (void)
 {
-  char *msg = emalloc (sizeof ("Passed"));
-  strcpy (msg, "Passed");
-  return msg;
+  return strdup ("Passed");
 }
 
-#ifdef _POSIX_VERSION
+#if defined(HAVE_FORK) && HAVE_FORK==1
 static TestResult *
 tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
 {
   pid_t pid_w;
   pid_t pid;
   int status = 0;
+  struct timespec ts_start = { 0, 0 }, ts_end = {
+  0, 0};
+
+  timer_t timerid;
+  struct itimerspec timer_spec;
+  TestResult *tr;
+
 
   pid = fork ();
   if (pid == -1)
@@ -368,19 +412,41 @@ tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
   if (pid == 0) {
     setpgid (0, 0);
     group_pid = getpgrp ();
-    tcase_run_checked_setup (sr, tc);
+    tr = tcase_run_checked_setup (sr, tc);
+    free (tr);
+    clock_gettime (check_get_clockid (), &ts_start);
     tfun->fn (i);
+    clock_gettime (check_get_clockid (), &ts_end);
     tcase_run_checked_teardown (tc);
+    send_duration_info (DIFF_IN_USEC (ts_start, ts_end));
     exit (EXIT_SUCCESS);
   } else {
     group_pid = pid;
   }
 
   alarm_received = 0;
-  alarm (tc->timeout);
-  do {
-    pid_w = waitpid (pid, &status, 0);
-  } while (pid_w == -1);
+
+  if (timer_create (check_get_clockid (),
+          NULL /* fire SIGALRM if timer expires */ ,
+          &timerid) == 0) {
+    /* Set the timer to fire once */
+    timer_spec.it_value = tc->timeout;
+    timer_spec.it_interval.tv_sec = 0;
+    timer_spec.it_interval.tv_nsec = 0;
+    if (timer_settime (timerid, 0, &timer_spec, NULL) == 0) {
+      do {
+        pid_w = waitpid (pid, &status, 0);
+      }
+      while (pid_w == -1);
+    } else {
+      eprintf ("Error in call to timer_settime:", __FILE__, __LINE__);
+    }
+
+    /* If the timer has not fired, disable it */
+    timer_delete (timerid);
+  } else {
+    eprintf ("Error in call to timer_create:", __FILE__, __LINE__);
+  }
 
   killpg (pid, SIGKILL);        /* Kill remaining processes. */
 
@@ -391,28 +457,30 @@ tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
 static TestResult *
 receive_result_info_fork (const char *tcname,
     const char *tname,
-    int iter, int status, int expected_signal, unsigned char allowed_exit_value)
+    int iter, int status, int expected_signal, signed char allowed_exit_value)
 {
   TestResult *tr;
 
   tr = receive_test_result (waserror (status, expected_signal));
-  if (tr == NULL)
+  if (tr == NULL) {
     eprintf ("Failed to receive test result", __FILE__, __LINE__);
-  tr->tcname = tcname;
-  tr->tname = tname;
-  tr->iter = iter;
-  set_fork_info (tr, status, expected_signal, allowed_exit_value);
+  } else {
+    tr->tcname = tcname;
+    tr->tname = tname;
+    tr->iter = iter;
+    set_fork_info (tr, status, expected_signal, allowed_exit_value);
+  }
 
   return tr;
 }
 
 static void
 set_fork_info (TestResult * tr, int status, int signal_expected,
-    unsigned char allowed_exit_value)
+    signed char allowed_exit_value)
 {
   int was_sig = WIFSIGNALED (status);
   int was_exit = WIFEXITED (status);
-  int exit_status = WEXITSTATUS (status);
+  signed char exit_status = WEXITSTATUS (status);
   int signal_received = WTERMSIG (status);
 
   if (was_sig) {
@@ -420,23 +488,38 @@ set_fork_info (TestResult * tr, int status, int signal_expected,
       if (alarm_received) {
         /* Got alarm instead of signal */
         tr->rtype = CK_ERROR;
+        if (tr->msg != NULL) {
+          free (tr->msg);
+        }
         tr->msg = signal_error_msg (signal_received, signal_expected);
       } else {
         tr->rtype = CK_PASS;
+        if (tr->msg != NULL) {
+          free (tr->msg);
+        }
         tr->msg = pass_msg ();
       }
     } else if (signal_expected != 0) {
       /* signal received, but not the expected one */
       tr->rtype = CK_ERROR;
+      if (tr->msg != NULL) {
+        free (tr->msg);
+      }
       tr->msg = signal_error_msg (signal_received, signal_expected);
     } else {
       /* signal received and none expected */
       tr->rtype = CK_ERROR;
+      if (tr->msg != NULL) {
+        free (tr->msg);
+      }
       tr->msg = signal_msg (signal_received);
     }
   } else if (signal_expected == 0) {
     if (was_exit && exit_status == allowed_exit_value) {
       tr->rtype = CK_PASS;
+      if (tr->msg != NULL) {
+        free (tr->msg);
+      }
       tr->msg = pass_msg ();
     } else if (was_exit && exit_status != allowed_exit_value) {
       if (tr->msg == NULL) {    /* early exit */
@@ -448,11 +531,15 @@ set_fork_info (TestResult * tr, int status, int signal_expected,
     }
   } else {                      /* a signal was expected and none raised */
     if (was_exit) {
+      if (tr->msg != NULL) {
+        free (tr->msg);
+      }
       tr->msg = exit_msg (exit_status);
-      if (exit_status == allowed_exit_value)
+      if (exit_status == allowed_exit_value) {
         tr->rtype = CK_FAILURE; /* normal exit status */
-      else
+      } else {
         tr->rtype = CK_FAILURE; /* early exit */
+      }
     }
   }
 }
@@ -460,7 +547,8 @@ set_fork_info (TestResult * tr, int status, int signal_expected,
 static char *
 signal_msg (int signal)
 {
-  char *msg = emalloc (MSG_LEN);        /* free'd by caller */
+  char *msg = (char *) emalloc (MSG_LEN);       /* free'd by caller */
+
   if (alarm_received) {
     snprintf (msg, MSG_LEN, "Test timeout expired");
   } else {
@@ -475,11 +563,13 @@ signal_error_msg (int signal_received, int signal_expected)
 {
   char *sig_r_str;
   char *sig_e_str;
-  char *msg = emalloc (MSG_LEN);        /* free'd by caller */
+  char *msg = (char *) emalloc (MSG_LEN);       /* free'd by caller */
+
   sig_r_str = strdup (strsignal (signal_received));
   sig_e_str = strdup (strsignal (signal_expected));
   if (alarm_received) {
-    snprintf (msg, MSG_LEN, "Test timeout expired, expected signal %d (%s)",
+    snprintf (msg, MSG_LEN,
+        "Test timeout expired, expected signal %d (%s)",
         signal_expected, sig_e_str);
   } else {
     snprintf (msg, MSG_LEN, "Received signal %d (%s), expected %d (%s)",
@@ -493,7 +583,8 @@ signal_error_msg (int signal_received, int signal_expected)
 static char *
 exit_msg (int exitval)
 {
-  char *msg = emalloc (MSG_LEN);        /* free'd by caller */
+  char *msg = (char *) emalloc (MSG_LEN);       /* free'd by caller */
+
   snprintf (msg, MSG_LEN, "Early exit with return value %d", exitval);
   return msg;
 }
@@ -509,24 +600,29 @@ waserror (int status, int signal_expected)
   return ((was_sig && (signal_received != signal_expected)) ||
       (was_exit && exit_status != 0));
 }
-#endif /* _POSIX_VERSION */
+#endif /* HAVE_FORK */
 
 enum fork_status
 srunner_fork_status (SRunner * sr)
 {
   if (sr->fstat == CK_FORK_GETENV) {
     char *env = getenv ("CK_FORK");
+
     if (env == NULL)
+#if defined(HAVE_FORK) && HAVE_FORK==1
       return CK_FORK;
+#else
+      return CK_NOFORK;
+#endif
     if (strcmp (env, "no") == 0)
       return CK_NOFORK;
     else {
-#ifdef _POSIX_VERSION
+#if defined(HAVE_FORK) && HAVE_FORK==1
       return CK_FORK;
-#else /* _POSIX_VERSION */
+#else /* HAVE_FORK */
       eprintf ("This version does not support fork", __FILE__, __LINE__);
       return CK_NOFORK;
-#endif /* _POSIX_VERSION */
+#endif /* HAVE_FORK */
     }
   } else
     return sr->fstat;
@@ -535,16 +631,38 @@ srunner_fork_status (SRunner * sr)
 void
 srunner_set_fork_status (SRunner * sr, enum fork_status fstat)
 {
+#if !defined(HAVE_FORK) || HAVE_FORK==0
+  /* If fork() is unavailable, do not allow a fork mode to be set */
+  if (fstat != CK_NOFORK) {
+    eprintf ("This version does not support fork", __FILE__, __LINE__);
+  }
+#endif /* ! HAVE_FORK */
   sr->fstat = fstat;
 }
 
 void
 srunner_run_all (SRunner * sr, enum print_output print_mode)
 {
-#ifdef _POSIX_VERSION
+  srunner_run (sr, NULL,        /* All test suites.  */
+      NULL,                     /* All test cases.   */
+      print_mode);
+}
+
+void
+srunner_run (SRunner * sr, const char *sname, const char *tcname,
+    enum print_output print_mode)
+{
+#if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
   struct sigaction old_action;
   struct sigaction new_action;
-#endif /* _POSIX_VERSION */
+#endif /* HAVE_SIGACTION && HAVE_FORK */
+
+  /*  Get the selected test suite and test case from the
+     environment.  */
+  if (!tcname)
+    tcname = getenv ("CK_RUN_CASE");
+  if (!sname)
+    sname = getenv ("CK_RUN_SUITE");
 
   if (sr == NULL)
     return;
@@ -552,50 +670,54 @@ srunner_run_all (SRunner * sr, enum print_output print_mode)
     eprintf ("Bad print_mode argument to srunner_run_all: %d",
         __FILE__, __LINE__, print_mode);
   }
-#ifdef _POSIX_VERSION
+#if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
   memset (&new_action, 0, sizeof new_action);
   new_action.sa_handler = sig_handler;
   sigaction (SIGALRM, &new_action, &old_action);
-#endif /* _POSIX_VERSION */
+#endif /* HAVE_SIGACTION && HAVE_FORK */
   srunner_run_init (sr, print_mode);
-  srunner_iterate_suites (sr, print_mode);
+  srunner_iterate_suites (sr, sname, tcname, print_mode);
   srunner_run_end (sr, print_mode);
-#ifdef _POSIX_VERSION
+#if defined(HAVE_SIGACTION) && defined(HAVE_FORK)
   sigaction (SIGALRM, &old_action, NULL);
-#endif /* _POSIX_VERSION */
+#endif /* HAVE_SIGACTION && HAVE_FORK */
 }
 
 pid_t
 check_fork (void)
 {
-#ifdef _POSIX_VERSION
+#if defined(HAVE_FORK) && HAVE_FORK==1
   pid_t pid = fork ();
+
   /* Set the process to a process group to be able to kill it easily. */
-  setpgid (pid, group_pid);
+  if (pid >= 0) {
+    setpgid (pid, group_pid);
+  }
   return pid;
-#else /* _POSIX_VERSION */
+#else /* HAVE_FORK */
   eprintf ("This version does not support fork", __FILE__, __LINE__);
   return 0;
-#endif /* _POSIX_VERSION */
+#endif /* HAVE_FORK */
 }
 
 void
 check_waitpid_and_exit (pid_t pid CK_ATTRIBUTE_UNUSED)
 {
-#ifdef _POSIX_VERSION
+#if defined(HAVE_FORK) && HAVE_FORK==1
   pid_t pid_w;
   int status;
 
   if (pid > 0) {
     do {
       pid_w = waitpid (pid, &status, 0);
-    } while (pid_w == -1);
+    }
+    while (pid_w == -1);
     if (waserror (status, 0)) {
       exit (EXIT_FAILURE);
     }
   }
   exit (EXIT_SUCCESS);
-#else /* _POSIX_VERSION */
+#else /* HAVE_FORK */
   eprintf ("This version does not support fork", __FILE__, __LINE__);
-#endif /* _POSIX_VERSION */
+#endif /* HAVE_FORK */
 }
index e66073e..972e29a 100644 (file)
@@ -18,7 +18,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#include "config.h"
+#include "../lib/libcompat.h"
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -79,11 +79,12 @@ char *
 ck_strdup_printf (const char *fmt, ...)
 {
   /* Guess we need no more than 100 bytes. */
-  int n, size = 100;
+  int n;
+  size_t size = 100;
   char *p;
   va_list ap;
 
-  p = emalloc (size);
+  p = (char *) emalloc (size);
 
   while (1) {
     /* Try to print in the allocated space. */
@@ -91,16 +92,16 @@ ck_strdup_printf (const char *fmt, ...)
     n = vsnprintf (p, size, fmt, ap);
     va_end (ap);
     /* If that worked, return the string. */
-    if (n > -1 && n < size)
+    if (n > -1 && n < (int) size)
       return p;
 
     /* Else try again with more space. */
     if (n > -1)                 /* C99 conform vsnprintf() */
-      size = n + 1;             /* precisely what is needed */
+      size = (size_t) n + 1;    /* precisely what is needed */
     else                        /* glibc 2.0 */
       size *= 2;                /* twice the old size */
 
-    p = erealloc (p, size);
+    p = (char *) erealloc (p, size);
   }
 }
 
@@ -108,6 +109,7 @@ static const char *
 tr_type_str (TestResult * tr)
 {
   const char *str = NULL;
+
   if (tr->ctx == CK_CTX_TEST) {
     if (tr->rtype == CK_PASS)
       str = "P";
index 9282a9a..bc70fb4 100644 (file)
 
 /* Return a string representation of the given TestResult.  Return
    value has been malloc'd, and must be freed by the caller */
-char *tr_str (TestResult *tr);
+char *tr_str (TestResult * tr);
 
 /* Return a string representation of the given TestResult message
    without the test id or result type. This is suitable for separate
    formatting of the test and the message. Return value has been 
    malloc'd, and must be freed by the caller */
-char *tr_short_str (TestResult *tr);
+char *tr_short_str (TestResult * tr);
 
 /* Return a string representation of the given SRunner's run
    statistics (% passed, num run, passed, errors, failures). Return
    value has been malloc'd, and must be freed by the caller
-*/ 
-char *sr_stat_str (SRunner *sr);
+*/
+char *sr_stat_str (SRunner * sr);
 
 char *ck_strdup_printf (const char *fmt, ...);
 
diff --git a/libs/gst/check/libcheck/clock_gettime.c b/libs/gst/check/libcheck/clock_gettime.c
new file mode 100644 (file)
index 0000000..3bce056
--- /dev/null
@@ -0,0 +1,65 @@
+#include "libcompat.h"
+
+#ifdef __MACH__
+#include <mach/clock.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <CoreServices/CoreServices.h>
+#include <unistd.h>
+#endif
+
+#define NANOSECONDS_PER_SECOND 1000000000
+
+
+
+int
+clock_gettime (clockid_t clk_id CK_ATTRIBUTE_UNUSED, struct timespec *ts)
+{
+
+#ifdef __MACH__
+  /* OS X does not have clock_gettime, use mach_absolute_time */
+
+  static mach_timebase_info_data_t sTimebaseInfo;
+  uint64_t rawTime;
+  uint64_t nanos;
+
+  rawTime = mach_absolute_time ();
+
+  /*
+   * OS X has a function to convert abs time to nano seconds: AbsoluteToNanoseconds
+   * However, the function may not be available as we may not have
+   * access to CoreServices. Because of this, we convert the abs time
+   * to nano seconds manually.
+   */
+
+  /*
+   * First grab the time base used on the system, if this is the first
+   * time we are being called. We can check if the value is uninitialized,
+   * as the denominator will be zero. 
+   */
+  if (sTimebaseInfo.denom == 0) {
+    (void) mach_timebase_info (&sTimebaseInfo);
+  }
+
+  /* 
+   * Do the conversion. We hope that the multiplication doesn't 
+   * overflow; the price you pay for working in fixed point.
+   */
+  nanos = rawTime * sTimebaseInfo.numer / sTimebaseInfo.denom;
+
+  /* 
+   * Fill in the timespec container 
+   */
+  ts->tv_sec = nanos / NANOSECONDS_PER_SECOND;
+  ts->tv_nsec = nanos - (ts->tv_sec * NANOSECONDS_PER_SECOND);
+#else
+  /* 
+   * As there is no function to fall back onto to get the current
+   * time, zero out the time so the caller will have a sane value. 
+   */
+  ts->tv_sec = 0;
+  ts->tv_nsec = 0;
+#endif
+
+  return 0;
+}
diff --git a/libs/gst/check/libcheck/libcompat.c b/libs/gst/check/libcheck/libcompat.c
new file mode 100644 (file)
index 0000000..f550d1d
--- /dev/null
@@ -0,0 +1,15 @@
+#include "libcompat.h"
+
+/* silence warnings about an empty library */
+void
+ck_do_nothing (void)
+{
+  assert (0);
+
+  /*
+   * to silence warning about this function actually
+   * returning, but being marked as noreturn. assert()
+   * must be marked as a function that returns.
+   */
+  exit (1);
+}
diff --git a/libs/gst/check/libcheck/libcompat.h b/libs/gst/check/libcheck/libcompat.h
new file mode 100644 (file)
index 0000000..f6afdf5
--- /dev/null
@@ -0,0 +1,213 @@
+#ifndef LIBCOMPAT_H
+#define LIBCOMPAT_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define GCC_VERSION_AT_LEAST(major, minor) \
+((__GNUC__ > (major)) || \
+ (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+#else
+#define GCC_VERSION_AT_LEAST(major, minor) 0
+#endif
+
+#if GCC_VERSION_AT_LEAST(2,95)
+#define CK_ATTRIBUTE_UNUSED __attribute__ ((unused))
+#else
+#define CK_ATTRIBUTE_UNUSED
+#endif /* GCC 2.95 */
+
+#if GCC_VERSION_AT_LEAST(2,5)
+#define CK_ATTRIBUTE_NORETURN __attribute__ ((noreturn))
+#else
+#define CK_ATTRIBUTE_NORETURN
+#endif /* GCC 2.5 */
+
+/*
+ * Used for MSVC to create the export attribute
+ * CK_DLL_EXP is defined during the compilation of the library
+ * on the command line.
+ */
+#ifndef CK_DLL_EXP
+#define CK_DLL_EXP
+#endif
+
+#if _MSC_VER
+#include <WinSock2.h>           /* struct timeval, API used in gettimeofday implementation */
+#include <io.h>                 /* read, write */
+#include <process.h>            /* getpid */
+#endif /* _MSC_VER */
+
+/* defines size_t */
+#include <sys/types.h>
+
+/* provides assert */
+#include <assert.h>
+
+/* defines FILE */
+#include <stdio.h>
+
+/* defines exit() */
+#include <stdlib.h>
+
+/* provides localtime and struct tm */
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif /* !HAVE_SYS_TIME_H */
+#include <time.h>
+
+/* declares fork(), _POSIX_VERSION.  according to Autoconf.info,
+   unistd.h defines _POSIX_VERSION if the system is POSIX-compliant,
+   so we will use this as a test for all things uniquely provided by
+   POSIX like sigaction() and fork() */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+/* declares pthread_create and friends */
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+/* replacement functions for broken originals */
+#if !HAVE_DECL_ALARM
+CK_DLL_EXP unsigned int alarm (unsigned int seconds);
+#endif /* !HAVE_DECL_ALARM */
+
+#if !HAVE_MALLOC
+CK_DLL_EXP void *rpl_malloc (size_t n);
+#endif /* !HAVE_MALLOC */
+
+#if !HAVE_REALLOC
+CK_DLL_EXP void *rpl_realloc (void *p, size_t n);
+#endif /* !HAVE_REALLOC */
+
+#if !HAVE_GETPID && HAVE__GETPID
+#define getpid _getpid
+#endif /* !HAVE_GETPID && HAVE__GETPID */
+
+#if !HAVE_GETTIMEOFDAY
+CK_DLL_EXP int gettimeofday (struct timeval *tv, void *tz);
+#endif /* !HAVE_GETTIMEOFDAY */
+
+#if !HAVE_DECL_LOCALTIME_R
+#if !defined(localtime_r)
+CK_DLL_EXP struct tm *localtime_r (const time_t * clock, struct tm *result);
+#endif
+#endif /* !HAVE_DECL_LOCALTIME_R */
+
+#if !HAVE_DECL_STRDUP && !HAVE__STRDUP
+CK_DLL_EXP char *strdup (const char *str);
+#elif !HAVE_DECL_STRDUP && HAVE__STRDUP
+#define strdup _strdup
+#endif /* !HAVE_DECL_STRDUP && HAVE__STRDUP */
+
+#if !HAVE_DECL_STRSIGNAL
+CK_DLL_EXP const char *strsignal (int sig);
+#endif /* !HAVE_DECL_STRSIGNAL */
+
+/*
+ * On systems where clock_gettime() is not available, or
+ * on systems where some clocks may not be supported, the
+ * definition for CLOCK_MONOTONIC and CLOCK_REALTIME may not
+ * be available. These should define which type of clock
+ * clock_gettime() should use. We define it here if it is
+ * not defined simply so the reimplementation can ignore it.
+ *
+ * We set the values of these clocks to some (hopefully)
+ * invalid value, to avoid the case where we define a
+ * clock with a valid value, and unintentionally use
+ * an actual good clock by accident.
+ */
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC -1
+#endif
+#ifndef CLOCK_REALTIME
+#define CLOCK_REALTIME -1
+#endif
+
+#ifndef HAVE_LIBRT
+
+#ifdef STRUCT_TIMESPEC_DEFINITION_MISSING
+/*
+ * The following structure is defined in POSIX 1003.1 for times
+ * specified in seconds and nanoseconds. If it is not defined in
+ * time.g, then we need to define it here
+ */
+struct timespec
+{
+  time_t tv_sec;
+  long tv_nsec;
+};
+#endif /* STRUCT_TIMESPEC_DEFINITION_MISSING */
+
+#ifdef STRUCT_ITIMERSPEC_DEFINITION_MISSING
+/* 
+ * The following structure is defined in POSIX.1b for timer start values and intervals.
+ * If it is not defined in time.h, then we need to define it here.
+ */
+struct itimerspec
+{
+  struct timespec it_interval;
+  struct timespec it_value;
+};
+#endif /* STRUCT_ITIMERSPEC_DEFINITION_MISSING */
+
+/* 
+ * Do a simple forward declaration in case the struct is not defined.
+ * In the versions of timer_create in libcompat, sigevent is never
+ * used.
+ */
+struct sigevent;
+
+CK_DLL_EXP int clock_gettime (clockid_t clk_id, struct timespec *ts);
+CK_DLL_EXP int timer_create (clockid_t clockid, struct sigevent *sevp,
+    timer_t * timerid);
+CK_DLL_EXP int timer_settime (timer_t timerid, int flags,
+    const struct itimerspec *new_value, struct itimerspec *old_value);
+CK_DLL_EXP int timer_delete (timer_t timerid);
+#endif /* HAVE_LIBRT */
+
+/*
+ * The following checks are to determine if the system's
+ * snprintf (or its variants) should be replaced with
+ * the C99 compliant version in libcompat.
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#if HAVE_STDARG_H
+#include <stdarg.h>
+
+#if !HAVE_VSNPRINTF
+CK_DLL_EXP int rpl_vsnprintf (char *, size_t, const char *, va_list);
+
+#define vsnprintf rpl_vsnprintf
+#endif
+#if !HAVE_SNPRINTF
+CK_DLL_EXP int rpl_snprintf (char *, size_t, const char *, ...);
+
+#define snprintf rpl_snprintf
+#endif
+#endif /* HAVE_STDARG_H */
+
+#if !HAVE_GETLINE
+CK_DLL_EXP ssize_t getline (char **lineptr, size_t * n, FILE * stream);
+#endif
+
+/* silence warnings about an empty library */
+CK_DLL_EXP void
+ck_do_nothing (void)
+    CK_ATTRIBUTE_NORETURN;
+
+#endif /* !LIBCOMPAT_H */
diff --git a/libs/gst/check/libcheck/localtime_r.c b/libs/gst/check/libcheck/localtime_r.c
new file mode 100644 (file)
index 0000000..682a1b4
--- /dev/null
@@ -0,0 +1,19 @@
+#include "libcompat.h"
+
+#if !defined(localtime_r)
+
+struct tm *
+localtime_r (const time_t * clock, struct tm *result)
+{
+  struct tm *now = localtime (clock);
+
+  if (now == NULL) {
+    return NULL;
+  } else {
+    *result = *now;
+  }
+
+  return result;
+}
+
+#endif /* !defined(localtime_r) */
diff --git a/libs/gst/check/libcheck/strsignal.c b/libs/gst/check/libcheck/strsignal.c
new file mode 100644 (file)
index 0000000..b79409b
--- /dev/null
@@ -0,0 +1,10 @@
+#include "libcompat.h"
+
+const char *
+strsignal (int sig)
+{
+  static char signame[40];
+
+  sprintf (signame, "SIG #%d", sig);
+  return signame;
+}
diff --git a/libs/gst/check/libcheck/timer_create.c b/libs/gst/check/libcheck/timer_create.c
new file mode 100644 (file)
index 0000000..a701781
--- /dev/null
@@ -0,0 +1,15 @@
+#include "libcompat.h"
+
+int
+timer_create (clockid_t clockid CK_ATTRIBUTE_UNUSED,
+    struct sigevent *sevp CK_ATTRIBUTE_UNUSED,
+    timer_t * timerid CK_ATTRIBUTE_UNUSED)
+{
+  /* 
+   * The create function does nothing. timer_settime will use
+   * alarm to set the timer, and timer_delete will stop the
+   * alarm
+   */
+
+  return 0;
+}
diff --git a/libs/gst/check/libcheck/timer_delete.c b/libs/gst/check/libcheck/timer_delete.c
new file mode 100644 (file)
index 0000000..cc3ae29
--- /dev/null
@@ -0,0 +1,33 @@
+#include "libcompat.h"
+
+int
+timer_delete (timer_t timerid CK_ATTRIBUTE_UNUSED)
+{
+#ifdef HAVE_SETITIMER
+  /*
+   * If the system does not have timer_settime() but does have
+   * setitimer() use that instead of alarm().
+   */
+  struct itimerval interval;
+
+  /*
+   * Setting values to '0' results in disabling the running timer.
+   */
+  interval.it_value.tv_sec = 0;
+  interval.it_value.tv_usec = 0;
+  interval.it_interval.tv_sec = 0;
+  interval.it_interval.tv_usec = 0;
+
+  return setitimer (ITIMER_REAL, &interval, NULL);
+#else
+  /*
+   * There is only one timer, that used by alarm.
+   * Setting alarm(0) will not set a new alarm, and
+   * will kill the previous timer.
+   */
+
+  alarm (0);
+
+  return 0;
+#endif
+}
diff --git a/libs/gst/check/libcheck/timer_settime.c b/libs/gst/check/libcheck/timer_settime.c
new file mode 100644 (file)
index 0000000..d09ba27
--- /dev/null
@@ -0,0 +1,37 @@
+#include "libcompat.h"
+
+int
+timer_settime (timer_t timerid CK_ATTRIBUTE_UNUSED,
+    int flags CK_ATTRIBUTE_UNUSED,
+    const struct itimerspec *new_value,
+    struct itimerspec *old_value CK_ATTRIBUTE_UNUSED)
+{
+#ifdef HAVE_SETITIMER
+  /*
+   * If the system does not have timer_settime() but does have
+   * setitimer() use that instead of alarm().
+   */
+  struct itimerval interval;
+
+  interval.it_value.tv_sec = new_value->it_value.tv_sec;
+  interval.it_value.tv_usec = new_value->it_value.tv_nsec / 1000;
+  interval.it_interval.tv_sec = new_value->it_interval.tv_sec;
+  interval.it_interval.tv_usec = new_value->it_interval.tv_nsec / 1000;
+
+  return setitimer (ITIMER_REAL, &interval, NULL);
+#else
+  int seconds = new_value->it_value.tv_sec;
+
+  /* 
+   * As the alarm() call has only second precision, if the caller
+   * specifies partial seconds, we round up to the nearest second.
+   */
+  if (new_value->it_value.tv_nsec > 0) {
+    seconds += 1;
+  }
+
+  alarm (seconds);
+
+  return 0;
+#endif
+}