check: Import version 0.9.14

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
This commit is contained in:
Sebastian Rasmussen 2014-11-15 12:53:32 +01:00 committed by Sebastian Dröge
parent f1c2cd60c3
commit f1df7aba8f
27 changed files with 2571 additions and 805 deletions

View file

@ -0,0 +1,8 @@
#include "libcompat.h"
unsigned int
alarm (unsigned int seconds CK_ATTRIBUTE_UNUSED)
{
assert (0);
return 0;
}

View file

@ -18,12 +18,13 @@
* 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"
@ -31,14 +32,18 @@
#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;
}

File diff suppressed because it is too large Load diff

View file

@ -18,22 +18,29 @@
* 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);

View file

@ -21,13 +21,20 @@
#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 */

View file

@ -21,97 +21,117 @@
#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);
TestResult *tr_create (void);
void tr_reset (TestResult * tr);
void tr_free (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
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 */

View 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));
}

View file

@ -24,33 +24,33 @@
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 */

View file

@ -18,16 +18,12 @@
* 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
@ -38,20 +34,11 @@
#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;
}

View file

@ -21,31 +21,35 @@
#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 */

View file

@ -18,12 +18,9 @@
* 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__);
}

View file

@ -24,13 +24,16 @@
/* 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 */

View file

@ -18,32 +18,37 @@
* 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);
n = fread (buf, 1, size, fdes);
nread += n;
size *= grow;
*buf = erealloc (*buf, size);
readloc = *buf + nread;
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;

View file

@ -22,10 +22,12 @@
#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 */

View 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++) {
@ -138,24 +124,40 @@ 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)

View file

@ -21,9 +21,11 @@
#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);

View file

@ -18,20 +18,16 @@
* 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) {
send_ctx_info (CK_CTX_SETUP);
}
f = list_val (l);
f->fun ();
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);
/* 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 (fork_usage == CK_NOFORK) {
send_ctx_info (CK_CTX_SETUP);
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 void
srunner_run_teardown (List * l)
static int
srunner_run_unchecked_setup (SRunner * sr, TCase * tc)
{
Fixture *f;
TestResult *tr = NULL;
int rval = 1;
for (list_front (l); !list_at_end (l); list_advance (l)) {
f = list_val (l);
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 * fixture_list, enum fork_status fork_usage)
{
Fixture *fixture;
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 */
}

View 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";

View file

@ -23,19 +23,19 @@
/* 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, ...);

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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 */

View file

@ -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) */

View file

@ -0,0 +1,10 @@
#include "libcompat.h"
const char *
strsignal (int sig)
{
static char signame[40];
sprintf (signame, "SIG #%d", sig);
return signame;
}

View file

@ -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;
}

View file

@ -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
}

View file

@ -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
}