mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-11 05:14:46 -04:00
Refactor unit tests using my spiffy new "tinytest" framework.
The big win here is that we can get process-level isolation. This has been tested to work okay on at least Linux and Win32. Only the tests in regress.c have been converted wrapped in the new wrapper functions; the others are still on the old system. svn:r1073
This commit is contained in:
parent
39c8dbe073
commit
a8203b3490
@ -6,6 +6,7 @@ EXTRA_DIST = regress.rpc regress.gen.h regress.gen.c
|
|||||||
|
|
||||||
noinst_PROGRAMS = test-init test-eof test-weof test-time regress \
|
noinst_PROGRAMS = test-init test-eof test-weof test-time regress \
|
||||||
bench bench_cascade bench_http
|
bench bench_cascade bench_http
|
||||||
|
noinst_HEADERS = tinytest.h tinytest_macros.h regress.h
|
||||||
|
|
||||||
BUILT_SOURCES = regress.gen.c regress.gen.h
|
BUILT_SOURCES = regress.gen.c regress.gen.h
|
||||||
test_init_SOURCES = test-init.c
|
test_init_SOURCES = test-init.c
|
||||||
@ -16,9 +17,10 @@ test_weof_SOURCES = test-weof.c
|
|||||||
test_weof_LDADD = ../libevent_core.la
|
test_weof_LDADD = ../libevent_core.la
|
||||||
test_time_SOURCES = test-time.c
|
test_time_SOURCES = test-time.c
|
||||||
test_time_LDADD = ../libevent_core.la
|
test_time_LDADD = ../libevent_core.la
|
||||||
regress_SOURCES = regress.c regress.h regress_http.c regress_dns.c \
|
|
||||||
|
regress_SOURCES = regress.c regress_http.c regress_dns.c \
|
||||||
regress_rpc.c regress.gen.c regress.gen.h regress_et.c \
|
regress_rpc.c regress.gen.c regress.gen.h regress_et.c \
|
||||||
regress_util.c \
|
regress_util.c tinytest.c regress_main.c \
|
||||||
$(regress_pthread_SOURCES) $(regress_zlib_SOURCES)
|
$(regress_pthread_SOURCES) $(regress_zlib_SOURCES)
|
||||||
if PTHREADS
|
if PTHREADS
|
||||||
regress_pthread_SOURCES = regress_pthread.c
|
regress_pthread_SOURCES = regress_pthread.c
|
||||||
@ -30,6 +32,7 @@ regress_LDADD = ../libevent.la $(PTHREAD_LIBS) $(ZLIB_LIBS)
|
|||||||
regress_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat \
|
regress_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat \
|
||||||
-I$(top_srcdir)/include $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS)
|
-I$(top_srcdir)/include $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS)
|
||||||
regress_LDFLAGS = $(PTHREAD_CFLAGS)
|
regress_LDFLAGS = $(PTHREAD_CFLAGS)
|
||||||
|
|
||||||
bench_SOURCES = bench.c
|
bench_SOURCES = bench.c
|
||||||
bench_LDADD = ../libevent.la
|
bench_LDADD = ../libevent.la
|
||||||
bench_cascade_SOURCES = bench_cascade.c
|
bench_cascade_SOURCES = bench_cascade.c
|
||||||
|
282
test/regress.c
282
test/regress.c
@ -75,7 +75,9 @@
|
|||||||
|
|
||||||
int pair[2];
|
int pair[2];
|
||||||
int test_ok;
|
int test_ok;
|
||||||
static int called;
|
int called;
|
||||||
|
struct event_base *global_base;
|
||||||
|
|
||||||
static char wbuf[4096];
|
static char wbuf[4096];
|
||||||
static char rbuf[4096];
|
static char rbuf[4096];
|
||||||
static int woff;
|
static int woff;
|
||||||
@ -83,7 +85,8 @@ static int roff;
|
|||||||
static int usepersist;
|
static int usepersist;
|
||||||
static struct timeval tset;
|
static struct timeval tset;
|
||||||
static struct timeval tcalled;
|
static struct timeval tcalled;
|
||||||
static struct event_base *global_base;
|
|
||||||
|
|
||||||
|
|
||||||
#define TEST1 "this is a test"
|
#define TEST1 "this is a test"
|
||||||
#define SECONDS 1
|
#define SECONDS 1
|
||||||
@ -255,6 +258,8 @@ combined_write_cb(int fd, short event, void *arg)
|
|||||||
static int
|
static int
|
||||||
setup_test(const char *name)
|
setup_test(const char *name)
|
||||||
{
|
{
|
||||||
|
if (in_legacy_test_wrapper)
|
||||||
|
return 0;
|
||||||
|
|
||||||
fprintf(stdout, "%s", name);
|
fprintf(stdout, "%s", name);
|
||||||
|
|
||||||
@ -277,6 +282,9 @@ setup_test(const char *name)
|
|||||||
static int
|
static int
|
||||||
cleanup_test(void)
|
cleanup_test(void)
|
||||||
{
|
{
|
||||||
|
if (in_legacy_test_wrapper)
|
||||||
|
return 0;
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
close(pair[0]);
|
close(pair[0]);
|
||||||
close(pair[1]);
|
close(pair[1]);
|
||||||
@ -491,8 +499,6 @@ test_persistent_timeout(void)
|
|||||||
struct event ev;
|
struct event ev;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
setup_test("Periodic timeout via EV_PERSIST: ");
|
|
||||||
|
|
||||||
timerclear(&tv);
|
timerclear(&tv);
|
||||||
tv.tv_usec = 10000;
|
tv.tv_usec = 10000;
|
||||||
|
|
||||||
@ -504,7 +510,6 @@ test_persistent_timeout(void)
|
|||||||
|
|
||||||
event_del(&ev);
|
event_del(&ev);
|
||||||
|
|
||||||
cleanup_test();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
@ -1077,7 +1082,7 @@ test_nonpersist_readd(void)
|
|||||||
cleanup_test();
|
cleanup_test();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* validates that an evbuffer is good */
|
/* Validates that an evbuffer is good. */
|
||||||
static void
|
static void
|
||||||
evbuffer_validate(struct evbuffer *buf)
|
evbuffer_validate(struct evbuffer *buf)
|
||||||
{
|
{
|
||||||
@ -1520,7 +1525,7 @@ test_evbuffer_iterative(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_evbuffer_find(void)
|
test_evbuffer_find(void *ptr)
|
||||||
{
|
{
|
||||||
u_char* p;
|
u_char* p;
|
||||||
const char* test1 = "1234567890\r\n";
|
const char* test1 = "1234567890\r\n";
|
||||||
@ -1531,7 +1536,6 @@ test_evbuffer_find(void)
|
|||||||
struct evbuffer * buf = evbuffer_new();
|
struct evbuffer * buf = evbuffer_new();
|
||||||
|
|
||||||
/* make sure evbuffer_find doesn't match past the end of the buffer */
|
/* make sure evbuffer_find doesn't match past the end of the buffer */
|
||||||
fprintf(stdout, "Testing evbuffer_find 1: ");
|
|
||||||
evbuffer_add(buf, (u_char*)test1, strlen(test1));
|
evbuffer_add(buf, (u_char*)test1, strlen(test1));
|
||||||
evbuffer_validate(buf);
|
evbuffer_validate(buf);
|
||||||
evbuffer_drain(buf, strlen(test1));
|
evbuffer_drain(buf, strlen(test1));
|
||||||
@ -1539,18 +1543,12 @@ test_evbuffer_find(void)
|
|||||||
evbuffer_add(buf, (u_char*)test2, strlen(test2));
|
evbuffer_add(buf, (u_char*)test2, strlen(test2));
|
||||||
evbuffer_validate(buf);
|
evbuffer_validate(buf);
|
||||||
p = evbuffer_find(buf, (u_char*)"\r\n", 2);
|
p = evbuffer_find(buf, (u_char*)"\r\n", 2);
|
||||||
if (p == NULL) {
|
tt_want(p == NULL);
|
||||||
fprintf(stdout, "OK\n");
|
|
||||||
} else {
|
|
||||||
fprintf(stdout, "FAILED\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* drain the buffer and do another find; in r309 this would
|
* drain the buffer and do another find; in r309 this would
|
||||||
* read past the allocated buffer causing a valgrind error.
|
* read past the allocated buffer causing a valgrind error.
|
||||||
*/
|
*/
|
||||||
fprintf(stdout, "Testing evbuffer_find 2: ");
|
|
||||||
evbuffer_drain(buf, strlen(test2));
|
evbuffer_drain(buf, strlen(test2));
|
||||||
evbuffer_validate(buf);
|
evbuffer_validate(buf);
|
||||||
for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
|
for (i = 0; i < EVBUFFER_INITIAL_LENGTH; ++i)
|
||||||
@ -1559,24 +1557,16 @@ test_evbuffer_find(void)
|
|||||||
evbuffer_add(buf, (u_char *)test3, EVBUFFER_INITIAL_LENGTH);
|
evbuffer_add(buf, (u_char *)test3, EVBUFFER_INITIAL_LENGTH);
|
||||||
evbuffer_validate(buf);
|
evbuffer_validate(buf);
|
||||||
p = evbuffer_find(buf, (u_char *)"xy", 2);
|
p = evbuffer_find(buf, (u_char *)"xy", 2);
|
||||||
if (p == NULL) {
|
tt_want(p == NULL);
|
||||||
printf("OK\n");
|
|
||||||
} else {
|
|
||||||
fprintf(stdout, "FAILED\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* simple test for match at end of allocated buffer */
|
/* simple test for match at end of allocated buffer */
|
||||||
fprintf(stdout, "Testing evbuffer_find 3: ");
|
|
||||||
p = evbuffer_find(buf, (u_char *)"ax", 2);
|
p = evbuffer_find(buf, (u_char *)"ax", 2);
|
||||||
if (p != NULL && strncmp((char*)p, "ax", 2) == 0) {
|
tt_assert(p != NULL);
|
||||||
printf("OK\n");
|
tt_want(strncmp((char*)p, "ax", 2) == 0);
|
||||||
} else {
|
|
||||||
fprintf(stdout, "FAILED\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
evbuffer_free(buf);
|
end:
|
||||||
|
if (buf)
|
||||||
|
evbuffer_free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1832,14 +1822,12 @@ test_priorities_cb(int fd, short what, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_priorities(int npriorities)
|
test_priorities_impl(int npriorities)
|
||||||
{
|
{
|
||||||
char buf[32];
|
|
||||||
struct test_pri_event one, two;
|
struct test_pri_event one, two;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
evutil_snprintf(buf, sizeof(buf), "Testing Priorities %d: ", npriorities);
|
TT_BLATHER(("Testing Priorities %d: ", npriorities));
|
||||||
setup_test(buf);
|
|
||||||
|
|
||||||
event_base_priority_init(global_base, npriorities);
|
event_base_priority_init(global_base, npriorities);
|
||||||
|
|
||||||
@ -1881,10 +1869,19 @@ test_priorities(int npriorities)
|
|||||||
if (one.count == 3 && two.count == 0)
|
if (one.count == 3 && two.count == 0)
|
||||||
test_ok = 1;
|
test_ok = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup_test();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_priorities(void)
|
||||||
|
{
|
||||||
|
test_priorities_impl(1);
|
||||||
|
if (test_ok)
|
||||||
|
test_priorities_impl(2);
|
||||||
|
if (test_ok)
|
||||||
|
test_priorities_impl(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_multiple_cb(int fd, short event, void *arg)
|
test_multiple_cb(int fd, short event, void *arg)
|
||||||
{
|
{
|
||||||
@ -2282,7 +2279,6 @@ test_evutil_strtoll(void)
|
|||||||
{
|
{
|
||||||
const char *s;
|
const char *s;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
setup_test("evutil_stroll: ");
|
|
||||||
test_ok = 0;
|
test_ok = 0;
|
||||||
|
|
||||||
if (evutil_strtoll("5000000000", NULL, 10) != ((ev_int64_t)5000000)*1000)
|
if (evutil_strtoll("5000000000", NULL, 10) != ((ev_int64_t)5000000)*1000)
|
||||||
@ -2298,142 +2294,139 @@ test_evutil_strtoll(void)
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
test_ok = 1;
|
test_ok = 1;
|
||||||
err:
|
err:
|
||||||
cleanup_test();
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_evutil_snprintf(void)
|
test_evutil_snprintf(void *ptr)
|
||||||
{
|
{
|
||||||
char buf[16];
|
char buf[16];
|
||||||
int r;
|
int r;
|
||||||
setup_test("evutil_snprintf: ");
|
|
||||||
test_ok = 0;
|
|
||||||
r = evutil_snprintf(buf, sizeof(buf), "%d %d", 50, 100);
|
r = evutil_snprintf(buf, sizeof(buf), "%d %d", 50, 100);
|
||||||
if (strcmp(buf, "50 100")) {
|
tt_str_op(buf, ==, "50 100");
|
||||||
fprintf(stderr, "buf='%s'\n", buf);
|
tt_int_op(r, ==, 6);
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (r != 6) {
|
|
||||||
fprintf(stderr, "r=%d\n", r);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = evutil_snprintf(buf, sizeof(buf), "longish %d", 1234567890);
|
r = evutil_snprintf(buf, sizeof(buf), "longish %d", 1234567890);
|
||||||
if (strcmp(buf, "longish 1234567")) {
|
tt_str_op(buf, ==, "longish 1234567");
|
||||||
fprintf(stderr, "buf='%s'\n", buf);
|
tt_int_op(r, ==, 18);
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (r != 18) {
|
|
||||||
fprintf(stderr, "r=%d\n", r);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
test_ok = 1;
|
end:
|
||||||
err:
|
;
|
||||||
cleanup_test();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_methods(void)
|
test_methods(void *ptr)
|
||||||
{
|
{
|
||||||
const char **methods = event_get_supported_methods();
|
const char **methods = event_get_supported_methods();
|
||||||
struct event_config *cfg;
|
struct event_config *cfg = NULL;
|
||||||
struct event_base *base;
|
struct event_base *base = NULL;
|
||||||
const char *backend;
|
const char *backend;
|
||||||
int n_methods = 0;
|
int n_methods = 0;
|
||||||
|
|
||||||
fprintf(stdout, "Testing supported methods: ");
|
tt_assert(methods);
|
||||||
|
|
||||||
if (methods == NULL) {
|
|
||||||
fprintf(stdout, "FAILED\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
backend = methods[0];
|
backend = methods[0];
|
||||||
while (*methods != NULL) {
|
while (*methods != NULL) {
|
||||||
fprintf(stdout, "%s ", *methods);
|
TT_BLATHER(("Support method: %s", *methods));
|
||||||
++methods;
|
++methods;
|
||||||
++n_methods;
|
++n_methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n_methods == 1) {
|
if (n_methods == 1) {
|
||||||
/* only one method supported; can't continue. */
|
/* only one method supported; can't continue. */
|
||||||
goto done;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg = event_config_new();
|
cfg = event_config_new();
|
||||||
assert(cfg != NULL);
|
assert(cfg != NULL);
|
||||||
|
|
||||||
assert(event_config_avoid_method(cfg, backend) == 0);
|
tt_int_op(event_config_avoid_method(cfg, backend), ==, 0);
|
||||||
|
|
||||||
base = event_base_new_with_config(cfg);
|
base = event_base_new_with_config(cfg);
|
||||||
if (base == NULL) {
|
tt_assert(base);
|
||||||
fprintf(stdout, "FAILED\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(backend, event_base_get_method(base)) == 0) {
|
tt_str_op(backend, !=, event_base_get_method(base));
|
||||||
fprintf(stdout, "FAILED\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
event_base_free(base);
|
end:
|
||||||
event_config_free(cfg);
|
if (base)
|
||||||
done:
|
event_base_free(base);
|
||||||
fprintf(stdout, "OK\n");
|
if (cfg)
|
||||||
|
event_config_free(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* All the flags we set */
|
||||||
|
#define TT_ISOLATED TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE
|
||||||
|
|
||||||
int
|
struct testcase_t legacy_testcases[] = {
|
||||||
main (int argc, char **argv)
|
/* Some converted-over tests */
|
||||||
{
|
{ "methods", test_methods, TT_FORK, NULL, NULL },
|
||||||
#ifdef WIN32
|
{ "evutil_snprintf", test_evutil_snprintf, 0, NULL, NULL },
|
||||||
WORD wVersionRequested;
|
|
||||||
WSADATA wsaData;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
wVersionRequested = MAKEWORD( 2, 2 );
|
/* These are still using the old API */
|
||||||
|
LEGACY(evutil_strtoll, 0),
|
||||||
|
LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),
|
||||||
|
LEGACY(priorities, TT_FORK|TT_NEED_BASE),
|
||||||
|
|
||||||
err = WSAStartup( wVersionRequested, &wsaData );
|
/* These need to fork because of evbuffer_validate. Otherwise
|
||||||
#endif
|
* they'd be fine in the main process, since they don't mess
|
||||||
|
* with global state. */
|
||||||
|
LEGACY(evbuffer, TT_FORK),
|
||||||
|
LEGACY(evbuffer_reference, TT_FORK),
|
||||||
|
LEGACY(evbuffer_iterative, TT_FORK),
|
||||||
|
LEGACY(evbuffer_readln, TT_FORK),
|
||||||
|
{ "evbuffer_find", test_evbuffer_find, TT_FORK, NULL, NULL },
|
||||||
|
|
||||||
|
LEGACY(bufferevent, TT_ISOLATED),
|
||||||
|
LEGACY(bufferevent_watermarks, TT_ISOLATED),
|
||||||
|
LEGACY(bufferevent_filters, TT_ISOLATED),
|
||||||
|
|
||||||
|
LEGACY(free_active_base, TT_FORK|TT_NEED_BASE),
|
||||||
|
LEGACY(event_base_new, TT_FORK|TT_NEED_SOCKETPAIR),
|
||||||
|
|
||||||
|
/* These legacy tests may not all need all of these flags. */
|
||||||
|
LEGACY(simpleread, TT_ISOLATED),
|
||||||
|
LEGACY(simpleread_multiple, TT_ISOLATED),
|
||||||
|
LEGACY(simplewrite, TT_ISOLATED),
|
||||||
|
LEGACY(multiple, TT_ISOLATED),
|
||||||
|
LEGACY(persistent, TT_ISOLATED),
|
||||||
|
LEGACY(combined, TT_ISOLATED),
|
||||||
|
LEGACY(simpletimeout, TT_ISOLATED),
|
||||||
|
LEGACY(loopbreak, TT_ISOLATED),
|
||||||
|
LEGACY(loopexit, TT_ISOLATED),
|
||||||
|
LEGACY(loopexit_multiple, TT_ISOLATED),
|
||||||
|
LEGACY(nonpersist_readd, TT_ISOLATED),
|
||||||
|
LEGACY(multiple_events_for_same_fd, TT_ISOLATED),
|
||||||
|
LEGACY(want_only_once, TT_ISOLATED),
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
|
LEGACY(fork, TT_ISOLATED),
|
||||||
return (1);
|
|
||||||
#endif
|
#endif
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
|
||||||
|
|
||||||
test_methods();
|
END_OF_TESTCASES
|
||||||
|
};
|
||||||
|
|
||||||
|
struct testcase_t signal_testcases[] = {
|
||||||
|
#ifndef WIN32
|
||||||
|
LEGACY(simplesignal, TT_ISOLATED),
|
||||||
|
LEGACY(multiplesignal, TT_ISOLATED),
|
||||||
|
LEGACY(immediatesignal, TT_ISOLATED),
|
||||||
|
LEGACY(signal_dealloc, TT_ISOLATED),
|
||||||
|
LEGACY(signal_pipeloss, TT_ISOLATED),
|
||||||
|
LEGACY(signal_switchbase, TT_ISOLATED),
|
||||||
|
LEGACY(signal_restore, TT_ISOLATED),
|
||||||
|
LEGACY(signal_assert, TT_ISOLATED),
|
||||||
|
LEGACY(signal_while_processing, TT_ISOLATED),
|
||||||
|
#endif
|
||||||
|
END_OF_TESTCASES
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
legacy_main(void)
|
||||||
|
{
|
||||||
/* Initalize the event library */
|
/* Initalize the event library */
|
||||||
global_base = event_init();
|
global_base = event_init();
|
||||||
|
|
||||||
test_evutil_strtoll();
|
|
||||||
test_evutil_snprintf();
|
|
||||||
util_suite();
|
|
||||||
|
|
||||||
test_persistent_timeout();
|
|
||||||
|
|
||||||
/* use the global event base and need to be called first */
|
|
||||||
test_priorities(1);
|
|
||||||
test_priorities(2);
|
|
||||||
test_priorities(3);
|
|
||||||
|
|
||||||
test_evbuffer();
|
|
||||||
test_evbuffer_reference();
|
|
||||||
test_evbuffer_iterative();
|
|
||||||
test_evbuffer_readln();
|
|
||||||
test_evbuffer_find();
|
|
||||||
|
|
||||||
test_bufferevent();
|
|
||||||
test_bufferevent_watermarks();
|
|
||||||
test_bufferevent_filters();
|
|
||||||
|
|
||||||
test_free_active_base();
|
|
||||||
|
|
||||||
test_event_base_new();
|
|
||||||
|
|
||||||
#if defined(_EVENT_HAVE_PTHREADS) && !defined(_EVENT_DISABLE_THREAD_SUPPORT)
|
#if defined(_EVENT_HAVE_PTHREADS) && !defined(_EVENT_DISABLE_THREAD_SUPPORT)
|
||||||
regress_pthread();
|
regress_pthread();
|
||||||
#endif
|
#endif
|
||||||
@ -2442,32 +2435,6 @@ main (int argc, char **argv)
|
|||||||
regress_zlib();
|
regress_zlib();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
test_simpleread();
|
|
||||||
test_simpleread_multiple();
|
|
||||||
|
|
||||||
test_simplewrite();
|
|
||||||
|
|
||||||
test_multiple();
|
|
||||||
|
|
||||||
test_persistent();
|
|
||||||
|
|
||||||
test_combined();
|
|
||||||
|
|
||||||
test_simpletimeout();
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
test_fork();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
test_edgetriggered();
|
|
||||||
test_simplesignal();
|
|
||||||
test_multiplesignal();
|
|
||||||
test_immediatesignal();
|
|
||||||
#endif
|
|
||||||
test_loopexit();
|
|
||||||
test_loopbreak();
|
|
||||||
|
|
||||||
http_suite();
|
http_suite();
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
@ -2476,27 +2443,10 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
dns_suite();
|
dns_suite();
|
||||||
|
|
||||||
test_loopexit_multiple();
|
|
||||||
|
|
||||||
test_nonpersist_readd();
|
|
||||||
|
|
||||||
test_multiple_events_for_same_fd();
|
|
||||||
|
|
||||||
test_want_only_once();
|
|
||||||
|
|
||||||
evtag_test();
|
evtag_test();
|
||||||
|
|
||||||
rpc_test();
|
rpc_test();
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
test_signal_dealloc();
|
|
||||||
test_signal_pipeloss();
|
|
||||||
test_signal_switchbase();
|
|
||||||
test_signal_restore();
|
|
||||||
test_signal_assert();
|
|
||||||
test_signal_while_processing();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,15 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "tinytest.h"
|
||||||
|
#include "tinytest_macros.h"
|
||||||
|
|
||||||
|
extern struct testcase_t legacy_testcases[];
|
||||||
|
extern struct testcase_t util_testcases[];
|
||||||
|
extern struct testcase_t signal_testcases[];
|
||||||
|
|
||||||
|
int legacy_main(void);
|
||||||
|
|
||||||
void http_suite(void);
|
void http_suite(void);
|
||||||
void http_basic_test(void);
|
void http_basic_test(void);
|
||||||
|
|
||||||
@ -38,13 +47,30 @@ void rpc_suite(void);
|
|||||||
|
|
||||||
void dns_suite(void);
|
void dns_suite(void);
|
||||||
|
|
||||||
void util_suite(void);
|
|
||||||
|
|
||||||
void regress_pthread(void);
|
void regress_pthread(void);
|
||||||
void regress_zlib(void);
|
void regress_zlib(void);
|
||||||
|
|
||||||
void test_edgetriggered(void);
|
void test_edgetriggered(void);
|
||||||
|
|
||||||
|
/* Helpers to wrap old testcases */
|
||||||
|
extern int pair[2];
|
||||||
|
extern int test_ok;
|
||||||
|
extern int called;
|
||||||
|
extern struct event_base *global_base;
|
||||||
|
extern int in_legacy_test_wrapper;
|
||||||
|
|
||||||
|
extern const struct testcase_setup_t legacy_setup;
|
||||||
|
void run_legacy_test_fn(void *ptr);
|
||||||
|
|
||||||
|
/* A couple of flags that legacy_setup can support. */
|
||||||
|
#define TT_NEED_SOCKETPAIR TT_FIRST_USER_FLAG
|
||||||
|
#define TT_NEED_BASE (TT_FIRST_USER_FLAG<<1)
|
||||||
|
|
||||||
|
#define LEGACY(name,flags) \
|
||||||
|
{ #name, run_legacy_test_fn, flags, &legacy_setup, \
|
||||||
|
test_## name }
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include "regress.h"
|
#include "regress.h"
|
||||||
|
|
||||||
static int called = 0;
|
|
||||||
static int was_et = 0;
|
static int was_et = 0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
195
test/regress_main.c
Normal file
195
test/regress_main.c
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
|
||||||
|
* Copyright (c) 2007-2009 Niels Provos and Nick Mathewson
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "event-config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#ifdef _EVENT_HAVE_SYS_TIME_H
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <event2/util.h>
|
||||||
|
#include <event2/event.h>
|
||||||
|
#include <event2/event_compat.h>
|
||||||
|
|
||||||
|
#include "regress.h"
|
||||||
|
#include "tinytest.h"
|
||||||
|
#include "tinytest_macros.h"
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
/* Code to wrap up old legacy test cases that used setup() and cleanup(). */
|
||||||
|
|
||||||
|
/* This is set to true if we're inside a legacy test wrapper. It lets the
|
||||||
|
setup() and cleanup() functions in regress.c know they're not needed.
|
||||||
|
*/
|
||||||
|
int in_legacy_test_wrapper = 0;
|
||||||
|
|
||||||
|
/* The "data" for a legacy test is just a pointer to the void fn(void)
|
||||||
|
function implementing the test case. We need to set up some globals,
|
||||||
|
though, since that's where legacy tests expect to find a socketpair
|
||||||
|
(sometimes) and a global event_base (sometimes).
|
||||||
|
*/
|
||||||
|
static void *
|
||||||
|
legacy_test_setup(const struct testcase_t *testcase)
|
||||||
|
{
|
||||||
|
if (testcase->flags & TT_NEED_SOCKETPAIR) {
|
||||||
|
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
|
||||||
|
fprintf(stderr, "%s: socketpair\n", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evutil_make_socket_nonblocking(pair[0]) == -1) {
|
||||||
|
fprintf(stderr, "fcntl(O_NONBLOCK)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evutil_make_socket_nonblocking(pair[1]) == -1) {
|
||||||
|
fprintf(stderr, "fcntl(O_NONBLOCK)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (testcase->flags & TT_NEED_BASE) {
|
||||||
|
global_base = event_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
return testcase->setup_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is the implementation of every legacy test case. It
|
||||||
|
sets test_ok to 0, invokes the test function, and tells tinytest that
|
||||||
|
the test failed if the test didn't set test_ok to 1.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
run_legacy_test_fn(void *ptr)
|
||||||
|
{
|
||||||
|
void (*fn)(void);
|
||||||
|
test_ok = called = 0;
|
||||||
|
fn = ptr;
|
||||||
|
|
||||||
|
in_legacy_test_wrapper = 1;
|
||||||
|
fn(); /* This part actually calls the test */
|
||||||
|
in_legacy_test_wrapper = 0;
|
||||||
|
|
||||||
|
if (!test_ok)
|
||||||
|
tt_abort_msg("Legacy unit test failed");
|
||||||
|
|
||||||
|
end:
|
||||||
|
test_ok = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function doesn't have to clean up ptr (which is just a pointer
|
||||||
|
to the test function), but it may need to close the socketpair or
|
||||||
|
free the event_base.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
legacy_test_cleanup(const struct testcase_t *testcase, void *ptr)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
if (testcase->flags & TT_NEED_SOCKETPAIR) {
|
||||||
|
if (pair[0] != -1)
|
||||||
|
EVUTIL_CLOSESOCKET(pair[0]);
|
||||||
|
if (pair[1] != -1)
|
||||||
|
EVUTIL_CLOSESOCKET(pair[1]);
|
||||||
|
pair[0] = pair[1] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testcase->flags & TT_NEED_BASE) {
|
||||||
|
event_base_free(global_base);
|
||||||
|
global_base = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct testcase_setup_t legacy_setup = {
|
||||||
|
legacy_test_setup, legacy_test_cleanup
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
|
||||||
|
struct testgroup_t testgroups[] = {
|
||||||
|
{ "main/", legacy_testcases },
|
||||||
|
{ "signal/", signal_testcases },
|
||||||
|
{ "util/", util_testcases },
|
||||||
|
END_OF_GROUPS
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
WORD wVersionRequested;
|
||||||
|
WSADATA wsaData;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
wVersionRequested = MAKEWORD(2, 2);
|
||||||
|
|
||||||
|
err = WSAStartup(wVersionRequested, &wsaData);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (tinytest_main(argc,argv,testgroups))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
in_legacy_test_wrapper = 0;
|
||||||
|
return legacy_main();
|
||||||
|
}
|
||||||
|
|
@ -49,7 +49,7 @@
|
|||||||
#include "event2/util.h"
|
#include "event2/util.h"
|
||||||
#include "../ipv6-internal.h"
|
#include "../ipv6-internal.h"
|
||||||
|
|
||||||
void util_suite(void);
|
#include "regress.h"
|
||||||
|
|
||||||
enum entry_status { NORMAL, CANONICAL, BAD };
|
enum entry_status { NORMAL, CANONICAL, BAD };
|
||||||
|
|
||||||
@ -97,12 +97,9 @@ static struct ipv6_entry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
regress_ipv4_parse(void)
|
regress_ipv4_parse(void *ptr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int ok = 1;
|
|
||||||
printf("Testing IPv4 parsing...");
|
|
||||||
|
|
||||||
for (i = 0; ipv4_entries[i].addr; ++i) {
|
for (i = 0; ipv4_entries[i].addr; ++i) {
|
||||||
char written[128];
|
char written[128];
|
||||||
struct ipv4_entry *ent = &ipv4_entries[i];
|
struct ipv4_entry *ent = &ipv4_entries[i];
|
||||||
@ -111,54 +108,44 @@ regress_ipv4_parse(void)
|
|||||||
r = evutil_inet_pton(AF_INET, ent->addr, &in);
|
r = evutil_inet_pton(AF_INET, ent->addr, &in);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
if (ent->status != BAD) {
|
if (ent->status != BAD) {
|
||||||
printf("%s did not parse, but it's a good address!\n",
|
TT_FAIL(("%s did not parse, but it's a good address!",
|
||||||
ent->addr);
|
ent->addr));
|
||||||
ok = 0;
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ent->status == BAD) {
|
if (ent->status == BAD) {
|
||||||
printf("%s parsed, but we expected an error\n", ent->addr);
|
TT_FAIL(("%s parsed, but we expected an error", ent->addr));
|
||||||
ok = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ntohl(in.s_addr) != ent->res) {
|
if (ntohl(in.s_addr) != ent->res) {
|
||||||
printf("%s parsed to %lx, but we expected %lx\n", ent->addr,
|
TT_FAIL(("%s parsed to %lx, but we expected %lx", ent->addr,
|
||||||
(unsigned long)ntohl(in.s_addr),
|
(unsigned long)ntohl(in.s_addr),
|
||||||
(unsigned long)ent->res);
|
(unsigned long)ent->res));
|
||||||
ok = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ent->status == CANONICAL) {
|
if (ent->status == CANONICAL) {
|
||||||
const char *w = evutil_inet_ntop(AF_INET, &in, written,
|
const char *w = evutil_inet_ntop(AF_INET, &in, written,
|
||||||
sizeof(written));
|
sizeof(written));
|
||||||
if (!w) {
|
if (!w) {
|
||||||
printf("Tried to write out %s; got NULL.\n", ent->addr);
|
TT_FAIL(("Tried to write out %s; got NULL.", ent->addr));
|
||||||
ok = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strcmp(written, ent->addr)) {
|
if (strcmp(written, ent->addr)) {
|
||||||
printf("Tried to write out %s; got %s\n", ent->addr, written);
|
TT_FAIL(("Tried to write out %s; got %s",
|
||||||
ok = 0;
|
ent->addr, written));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (!ok) {
|
|
||||||
printf("FAILED\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
printf("OK\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
regress_ipv6_parse(void)
|
regress_ipv6_parse(void *ptr)
|
||||||
{
|
{
|
||||||
#ifdef AF_INET6
|
#ifdef AF_INET6
|
||||||
int i, j;
|
int i, j;
|
||||||
int ok = 1;
|
|
||||||
printf("Testing IPv6 parsing...");
|
|
||||||
|
|
||||||
for (i = 0; ipv6_entries[i].addr; ++i) {
|
for (i = 0; ipv6_entries[i].addr; ++i) {
|
||||||
char written[128];
|
char written[128];
|
||||||
@ -167,16 +154,13 @@ regress_ipv6_parse(void)
|
|||||||
int r;
|
int r;
|
||||||
r = evutil_inet_pton(AF_INET6, ent->addr, &in6);
|
r = evutil_inet_pton(AF_INET6, ent->addr, &in6);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
if (ent->status != BAD) {
|
if (ent->status != BAD)
|
||||||
printf("%s did not parse, but it's a good address!\n",
|
TT_FAIL(("%s did not parse, but it's a good address!",
|
||||||
ent->addr);
|
ent->addr));
|
||||||
ok = 0;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ent->status == BAD) {
|
if (ent->status == BAD) {
|
||||||
printf("%s parsed, but we expected an error\n", ent->addr);
|
TT_FAIL(("%s parsed, but we expected an error", ent->addr));
|
||||||
ok = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (j = 0; j < 4; ++j) {
|
for (j = 0; j < 4; ++j) {
|
||||||
@ -187,8 +171,7 @@ regress_ipv6_parse(void)
|
|||||||
(in6.s6_addr[j*4+2] << 8) |
|
(in6.s6_addr[j*4+2] << 8) |
|
||||||
(in6.s6_addr[j*4+3]);
|
(in6.s6_addr[j*4+3]);
|
||||||
if (u != ent->res[j]) {
|
if (u != ent->res[j]) {
|
||||||
printf("%s did not parse as expected.\n", ent->addr);
|
TT_FAIL(("%s did not parse as expected.", ent->addr));
|
||||||
ok = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,25 +179,18 @@ regress_ipv6_parse(void)
|
|||||||
const char *w = evutil_inet_ntop(AF_INET6, &in6, written,
|
const char *w = evutil_inet_ntop(AF_INET6, &in6, written,
|
||||||
sizeof(written));
|
sizeof(written));
|
||||||
if (!w) {
|
if (!w) {
|
||||||
printf("Tried to write out %s; got NULL.\n", ent->addr);
|
TT_FAIL(("Tried to write out %s; got NULL.", ent->addr));
|
||||||
ok = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strcmp(written, ent->addr)) {
|
if (strcmp(written, ent->addr)) {
|
||||||
printf("Tried to write out %s; got %s\n", ent->addr, written);
|
TT_FAIL(("Tried to write out %s; got %s", ent->addr, written));
|
||||||
ok = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (!ok) {
|
|
||||||
printf("FAILED\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
printf("OK\n");
|
|
||||||
#else
|
#else
|
||||||
print("Skipping IPv6 address parsing.\n");
|
TT_BLATHER(("Skipping IPv6 address parsing."));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,10 +211,9 @@ static struct sa_port_ent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
regress_sockaddr_port_parse(void)
|
regress_sockaddr_port_parse(void *ptr)
|
||||||
{
|
{
|
||||||
struct sockaddr_storage ss;
|
struct sockaddr_storage ss;
|
||||||
int ok = 1;
|
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
for (i = 0; sa_port_ents[i].parse; ++i) {
|
for (i = 0; sa_port_ents[i].parse; ++i) {
|
||||||
@ -246,15 +221,11 @@ regress_sockaddr_port_parse(void)
|
|||||||
memset(&ss, 0, sizeof(ss));
|
memset(&ss, 0, sizeof(ss));
|
||||||
r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, sizeof(ss));
|
r = evutil_parse_sockaddr_port(ent->parse, (struct sockaddr*)&ss, sizeof(ss));
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (ent->sa_family) {
|
if (ent->sa_family)
|
||||||
printf("Couldn't parse %s!\n", ent->parse);
|
TT_FAIL(("Couldn't parse %s!", ent->parse));
|
||||||
ok = 0;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
} else if (! ent->sa_family) {
|
} else if (! ent->sa_family) {
|
||||||
printf("Shouldn't have been able to parse %s!\n",
|
TT_FAIL(("Shouldn't have been able to parse %s!", ent->parse));
|
||||||
ent->parse);
|
|
||||||
ok = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ent->sa_family == AF_INET) {
|
if (ent->sa_family == AF_INET) {
|
||||||
@ -267,11 +238,9 @@ regress_sockaddr_port_parse(void)
|
|||||||
sin.sin_port = htons(ent->port);
|
sin.sin_port = htons(ent->port);
|
||||||
r = evutil_inet_pton(AF_INET, ent->addr, &sin.sin_addr);
|
r = evutil_inet_pton(AF_INET, ent->addr, &sin.sin_addr);
|
||||||
if (1 != r) {
|
if (1 != r) {
|
||||||
printf("Couldn't parse ipv4 target %s.\n", ent->addr);
|
TT_FAIL(("Couldn't parse ipv4 target %s.", ent->addr));
|
||||||
ok = 0;
|
|
||||||
} else if (memcmp(&sin, &ss, sizeof(sin))) {
|
} else if (memcmp(&sin, &ss, sizeof(sin))) {
|
||||||
printf("Parse for %s was not as expected.\n", ent->parse);
|
TT_FAIL(("Parse for %s was not as expected.", ent->parse));
|
||||||
ok = 0;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_in6 sin6;
|
struct sockaddr_in6 sin6;
|
||||||
@ -283,26 +252,19 @@ regress_sockaddr_port_parse(void)
|
|||||||
sin6.sin6_port = htons(ent->port);
|
sin6.sin6_port = htons(ent->port);
|
||||||
r = evutil_inet_pton(AF_INET6, ent->addr, &sin6.sin6_addr);
|
r = evutil_inet_pton(AF_INET6, ent->addr, &sin6.sin6_addr);
|
||||||
if (1 != r) {
|
if (1 != r) {
|
||||||
printf("Couldn't parse ipv6 target %s.\n", ent->addr);
|
TT_FAIL(("Couldn't parse ipv6 target %s.", ent->addr));
|
||||||
ok = 0;
|
|
||||||
} else if (memcmp(&sin6, &ss, sizeof(sin6))) {
|
} else if (memcmp(&sin6, &ss, sizeof(sin6))) {
|
||||||
printf("Parse for %s was not as expected.\n", ent->parse);
|
TT_FAIL(("Parse for %s was not as expected.", ent->parse));
|
||||||
ok = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
printf("FAILED\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
printf("OK\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
struct testcase_t util_testcases[] = {
|
||||||
util_suite(void)
|
{ "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
|
||||||
{
|
{ "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
|
||||||
regress_ipv4_parse();
|
{ "sockaddr_port_parse", regress_sockaddr_port_parse, 0, NULL, NULL },
|
||||||
regress_ipv6_parse();
|
END_OF_TESTCASES,
|
||||||
regress_sockaddr_port_parse();
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
314
test/tinytest.c
Normal file
314
test/tinytest.c
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
/* tinytest.c -- Copyright 2009 Nick Mathewson
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tinytest.h"
|
||||||
|
#include "tinytest_macros.h"
|
||||||
|
|
||||||
|
#define LONGEST_TEST_NAME 16384
|
||||||
|
|
||||||
|
static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
|
||||||
|
static int n_ok = 0; /**< Number of tests that have passed */
|
||||||
|
static int n_bad = 0; /**< Number of tests that have failed. */
|
||||||
|
|
||||||
|
static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
|
||||||
|
static int opt_verbosity = 1; /**< 0==quiet,1==normal,2==verbose */
|
||||||
|
|
||||||
|
static int cur_test_outcome = 0; /**< True iff the current test has failed. */
|
||||||
|
const char *cur_test_prefix = NULL; /**< prefix of the current test group */
|
||||||
|
/** Name of the current test, if we haven't logged is yet. Used for --quiet */
|
||||||
|
const char *cur_test_name = NULL;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
/** Pointer to argv[0] for win32. */
|
||||||
|
static const char *commandname = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
_testcase_run_bare(const struct testcase_t *testcase)
|
||||||
|
{
|
||||||
|
void *env = NULL;
|
||||||
|
int outcome;
|
||||||
|
if (testcase->setup) {
|
||||||
|
env = testcase->setup->setup_fn(testcase);
|
||||||
|
assert(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_test_outcome = 1;
|
||||||
|
testcase->fn(env);
|
||||||
|
outcome = cur_test_outcome;
|
||||||
|
|
||||||
|
if (testcase->setup) {
|
||||||
|
if (testcase->setup->cleanup_fn(testcase, env) == 0)
|
||||||
|
outcome = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outcome;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_testcase_run_forked(const struct testgroup_t *group,
|
||||||
|
const struct testcase_t *testcase)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
/* Fork? On Win32? How primitive! We'll do what the smart kids do:
|
||||||
|
we'll invoke our own exe (whose name we recall from the command
|
||||||
|
line) with a command line that tells it to run just the test we
|
||||||
|
want, and this time without forking.
|
||||||
|
|
||||||
|
(No, threads aren't an option. The whole point of forking is to
|
||||||
|
share no state between tests.)
|
||||||
|
*/
|
||||||
|
int ok;
|
||||||
|
char buffer[LONGEST_TEST_NAME+256];
|
||||||
|
const char *verbosity;
|
||||||
|
STARTUPINFO si;
|
||||||
|
PROCESS_INFORMATION info;
|
||||||
|
DWORD exitcode;
|
||||||
|
|
||||||
|
if (!in_tinytest_main) {
|
||||||
|
printf("\nERROR. On Windows, _testcase_run_forked must be"
|
||||||
|
" called from within tinytest_main.\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (opt_verbosity)
|
||||||
|
printf("[forking] ");
|
||||||
|
|
||||||
|
verbosity = (opt_verbosity == 2) ? "--verbose" :
|
||||||
|
(opt_verbosity == 0) ? "--quiet" : "";
|
||||||
|
snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
|
||||||
|
commandname, verbosity, group->prefix, testcase->name);
|
||||||
|
|
||||||
|
memset(&si, 0, sizeof(si));
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
|
||||||
|
ok = CreateProcess(commandname, buffer, NULL, NULL, 0,
|
||||||
|
0, NULL, NULL, &si, &info);
|
||||||
|
if (!ok) {
|
||||||
|
printf("CreateProcess failed!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
WaitForSingleObject(info.hProcess, INFINITE);
|
||||||
|
GetExitCodeProcess(info.hProcess, &exitcode);
|
||||||
|
CloseHandle(info.hProcess);
|
||||||
|
CloseHandle(info.hThread);
|
||||||
|
return exitcode == 0;
|
||||||
|
#else
|
||||||
|
int outcome_pipe[2];
|
||||||
|
pid_t pid;
|
||||||
|
(void)group;
|
||||||
|
|
||||||
|
if (pipe(outcome_pipe))
|
||||||
|
perror("opening pipe");
|
||||||
|
|
||||||
|
if (opt_verbosity)
|
||||||
|
printf("[forking] ");
|
||||||
|
pid = fork();
|
||||||
|
if (!pid) {
|
||||||
|
/* child. */
|
||||||
|
int test_r, write_r;
|
||||||
|
close(outcome_pipe[0]);
|
||||||
|
test_r = _testcase_run_bare(testcase);
|
||||||
|
write_r = write(outcome_pipe[1], test_r ? "Y" : "N", 1);
|
||||||
|
if (write_r != 1) {
|
||||||
|
perror("write outcome to pipe");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
/* parent */
|
||||||
|
int status, r;
|
||||||
|
char b[1];
|
||||||
|
/* Close this now, so that if the other side closes it,
|
||||||
|
* our read fails. */
|
||||||
|
close(outcome_pipe[1]);
|
||||||
|
r = read(outcome_pipe[0], b, 1);
|
||||||
|
if (r == 0) {
|
||||||
|
printf("[Lost connection!] ");
|
||||||
|
return 0;
|
||||||
|
} else if (r != 1) {
|
||||||
|
perror("read outcome from pipe");
|
||||||
|
}
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
close(outcome_pipe[0]);
|
||||||
|
return b[0] == 'Y' ? 1 : 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
testcase_run_one(const struct testgroup_t *group,
|
||||||
|
const struct testcase_t *testcase)
|
||||||
|
{
|
||||||
|
int outcome;
|
||||||
|
|
||||||
|
if (testcase->flags & TT_SKIP) {
|
||||||
|
if (opt_verbosity)
|
||||||
|
printf("%s%s... SKIPPED\n",
|
||||||
|
group->prefix, testcase->name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_verbosity && !opt_forked)
|
||||||
|
printf("%s%s... ", group->prefix, testcase->name);
|
||||||
|
else {
|
||||||
|
cur_test_prefix = group->prefix;
|
||||||
|
cur_test_name = testcase->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((testcase->flags & TT_FORK) && !opt_forked) {
|
||||||
|
outcome = _testcase_run_forked(group, testcase);
|
||||||
|
} else {
|
||||||
|
outcome = _testcase_run_bare(testcase);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outcome) {
|
||||||
|
++n_ok;
|
||||||
|
if (opt_verbosity && !opt_forked)
|
||||||
|
puts(opt_verbosity==1?"OK":"");
|
||||||
|
} else {
|
||||||
|
++n_bad;
|
||||||
|
if (!opt_forked)
|
||||||
|
printf("\n [%s FAILED]\n", testcase->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_forked) {
|
||||||
|
exit(outcome ? 0 : 1);
|
||||||
|
} else {
|
||||||
|
return outcome;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_tinytest_set_flag(struct testgroup_t *groups, const char *arg, unsigned long flag)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
int length = LONGEST_TEST_NAME;
|
||||||
|
char fullname[LONGEST_TEST_NAME];
|
||||||
|
int found=0;
|
||||||
|
if (strstr(arg, ".."))
|
||||||
|
length = strstr(arg,"..")-arg;
|
||||||
|
for (i=0; groups[i].prefix; ++i) {
|
||||||
|
for (j=0; groups[i].cases[j].name; ++j) {
|
||||||
|
snprintf(fullname, sizeof(fullname), "%s%s",
|
||||||
|
groups[i].prefix, groups[i].cases[j].name);
|
||||||
|
if (!flag) /* Hack! */
|
||||||
|
printf(" %s\n", fullname);
|
||||||
|
if (!strncmp(fullname, arg, length)) {
|
||||||
|
groups[i].cases[j].flags |= flag;
|
||||||
|
++found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(struct testgroup_t *groups)
|
||||||
|
{
|
||||||
|
puts("Options are: --verbose --quiet");
|
||||||
|
puts("Known tests are:");
|
||||||
|
_tinytest_set_flag(groups, "..", 0);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tinytest_main(int c, const char **v, struct testgroup_t *groups)
|
||||||
|
{
|
||||||
|
int i, j, n=0;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
commandname = v[0];
|
||||||
|
#endif
|
||||||
|
for (i=1; i<c; ++i) {
|
||||||
|
if (v[i][0] == '-') {
|
||||||
|
if (!strcmp(v[i], "--RUNNING-FORKED"))
|
||||||
|
opt_forked = 1;
|
||||||
|
else if (!strcmp(v[i], "--quiet"))
|
||||||
|
opt_verbosity = 0;
|
||||||
|
else if (!strcmp(v[i], "--verbose"))
|
||||||
|
opt_verbosity = 2;
|
||||||
|
else if (!strcmp(v[i], "--help"))
|
||||||
|
usage(groups);
|
||||||
|
else {
|
||||||
|
printf("Unknown option %s. Try --help\n",v[i]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
++n;
|
||||||
|
if (!_tinytest_set_flag(groups, v[i], _TT_ENABLED)) {
|
||||||
|
printf("No such test as %s!\n", v[i]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!n)
|
||||||
|
_tinytest_set_flag(groups, "...", _TT_ENABLED);
|
||||||
|
|
||||||
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
|
|
||||||
|
++in_tinytest_main;
|
||||||
|
for (i=0; groups[i].prefix; ++i)
|
||||||
|
for (j=0; groups[i].cases[j].name; ++j)
|
||||||
|
if (groups[i].cases[j].flags & _TT_ENABLED)
|
||||||
|
testcase_run_one(&groups[i],
|
||||||
|
&groups[i].cases[j]);
|
||||||
|
|
||||||
|
--in_tinytest_main;
|
||||||
|
|
||||||
|
if (n_bad)
|
||||||
|
printf("%d TESTS FAILED.\n", n_bad);
|
||||||
|
return (n_bad == 0) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_tinytest_get_verbosity(void)
|
||||||
|
{
|
||||||
|
return opt_verbosity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_tinytest_set_test_failed(void)
|
||||||
|
{
|
||||||
|
if (opt_verbosity == 0 && cur_test_name) {
|
||||||
|
printf("%s%s... ", cur_test_prefix, cur_test_name);
|
||||||
|
cur_test_name = NULL;
|
||||||
|
}
|
||||||
|
cur_test_outcome = 0;
|
||||||
|
}
|
||||||
|
|
85
test/tinytest.h
Normal file
85
test/tinytest.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/* tinytest.h -- Copyright 2009 Nick Mathewson
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TINYTEST_H
|
||||||
|
#define _TINYTEST_H
|
||||||
|
|
||||||
|
/** Flag for a test that needs to run in a subprocess. */
|
||||||
|
#define TT_FORK (1<<0)
|
||||||
|
/** Runtime flag for a test we've decided to skip. */
|
||||||
|
#define TT_SKIP (1<<1)
|
||||||
|
/** Internal runtime flag for a test we've decided to run. */
|
||||||
|
#define _TT_ENABLED (1<<2)
|
||||||
|
/** If you add your own flags, make them start at this point. */
|
||||||
|
#define TT_FIRST_USER_FLAG (1<<3)
|
||||||
|
|
||||||
|
typedef void (*testcase_fn)(void *);
|
||||||
|
|
||||||
|
struct testcase_t;
|
||||||
|
|
||||||
|
/** Functions to initialize/teardown a structure for a testcase. */
|
||||||
|
struct testcase_setup_t {
|
||||||
|
/** Return a new structure for use by a given testcase. */
|
||||||
|
void *(*setup_fn)(const struct testcase_t *);
|
||||||
|
/** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
|
||||||
|
int (*cleanup_fn)(const struct testcase_t *, void *);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A single test-case that you can run. */
|
||||||
|
struct testcase_t {
|
||||||
|
const char *name; /**< An identifier for this case. */
|
||||||
|
testcase_fn fn; /**< The function to run to implement this case. */
|
||||||
|
unsigned long flags; /**< Bitfield of TT_* flags. */
|
||||||
|
const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
|
||||||
|
void *setup_data; /**< Extra data usable by setup function */
|
||||||
|
};
|
||||||
|
#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL }
|
||||||
|
|
||||||
|
/** A group of tests that are selectable together. */
|
||||||
|
struct testgroup_t {
|
||||||
|
const char *prefix; /**< Prefix to prepend to testnames. */
|
||||||
|
struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
|
||||||
|
};
|
||||||
|
#define END_OF_GROUPS { NULL, NULL}
|
||||||
|
|
||||||
|
/** Implementation: called from a test to indicate failure, before logging. */
|
||||||
|
void _tinytest_set_test_failed(void);
|
||||||
|
/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
|
||||||
|
int _tinytest_get_verbosity(void);
|
||||||
|
/** Implementation: Set a flag on tests matching a name; returns number
|
||||||
|
* of tests that matched. */
|
||||||
|
int _tinytest_set_flag(struct testgroup_t *, const char *, unsigned long);
|
||||||
|
|
||||||
|
/** Set all tests in 'groups' matching the name 'named' to be skipped. */
|
||||||
|
#define tinytest_skip(groups, named) \
|
||||||
|
_tinytest_set_flag(groups, named, TT_SKIP)
|
||||||
|
|
||||||
|
/** Run a single testcase in a single group. */
|
||||||
|
int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
|
||||||
|
/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
|
||||||
|
as selected from the command line. */
|
||||||
|
int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
|
||||||
|
|
||||||
|
#endif
|
215
test/tinytest_demo.c
Normal file
215
test/tinytest_demo.c
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/* tinytest_demo.c -- Copyright 2009 Nick Mathewson
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Welcome to the example file for tinytest! I'll show you how to set up
|
||||||
|
* some simple and not-so-simple testcases. */
|
||||||
|
|
||||||
|
/* Make sure you include these headers. */
|
||||||
|
#include "tinytest.h"
|
||||||
|
#include "tinytest_macros.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
/* First, let's see if strcmp is working. (All your test cases should be
|
||||||
|
* functions declared to take a single void * as) an argument. */
|
||||||
|
void
|
||||||
|
test_strcmp(void *data)
|
||||||
|
{
|
||||||
|
(void)data; /* This testcase takes no data. */
|
||||||
|
|
||||||
|
/* Let's make sure the empty string is equal to itself */
|
||||||
|
if (strcmp("","")) {
|
||||||
|
/* This macro tells tinytest to stop the current test
|
||||||
|
* and go straight to the "end" label. */
|
||||||
|
tt_abort_msg("The empty string was not equal to itself");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pretty often, calling tt_abort_msg to indicate failure is more
|
||||||
|
heavy-weight than you want. Instead, just say: */
|
||||||
|
tt_assert(strcmp("testcase", "testcase") == 0);
|
||||||
|
|
||||||
|
/* Occasionally, you don't want to stop the current testcase just
|
||||||
|
because a single assertion has failed. In that case, use
|
||||||
|
tt_want: */
|
||||||
|
tt_want(strcmp("tinytest", "testcase") > 0);
|
||||||
|
|
||||||
|
/* You can use the tt_*_op family of macros to compare values and to
|
||||||
|
fail unless they have the relationship you want. They produce
|
||||||
|
more useful output than tt_assert, since they display the actual
|
||||||
|
values of the failing things.
|
||||||
|
|
||||||
|
Fail unless strcmp("abc, "abc") == 0 */
|
||||||
|
tt_int_op(strcmp("abc", "abc"), ==, 0);
|
||||||
|
|
||||||
|
/* Fail unless strcmp("abc, "abcd") is less than 0 */
|
||||||
|
tt_int_op(strcmp("abc", "abcd"), < , 0);
|
||||||
|
|
||||||
|
/* Incidentally, there's a test_str_op that uses strcmp internally. */
|
||||||
|
tt_str_op("abc", <, "abcd");
|
||||||
|
|
||||||
|
|
||||||
|
/* Every test-case function needs to finish with an "end:"
|
||||||
|
label and (optionally) code to clean up local variables. */
|
||||||
|
end:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
/* Now let's mess with setup and teardown functions! These are handy if
|
||||||
|
you have a bunch of tests that all need a similar environment, and you
|
||||||
|
wnat to reconstruct that environment freshly for each one. */
|
||||||
|
|
||||||
|
/* First you declare a type to hold the environment info, and functions to
|
||||||
|
set it up and tear it down. */
|
||||||
|
struct data_buffer {
|
||||||
|
/* We're just going to have couple of character buffer. Using
|
||||||
|
setup/teardown functions is probably overkill for this case.
|
||||||
|
|
||||||
|
You could also do file descriptors, complicated handles, temporary
|
||||||
|
files, etc. */
|
||||||
|
char buffer1[512];
|
||||||
|
char buffer2[512];
|
||||||
|
};
|
||||||
|
/* The setup function needs to take a const struct testcase_t and return
|
||||||
|
void* */
|
||||||
|
void *
|
||||||
|
setup_data_buffer(const struct testcase_t *testcase)
|
||||||
|
{
|
||||||
|
struct data_buffer *db = malloc(sizeof(struct data_buffer));
|
||||||
|
|
||||||
|
/* If you had a complicated set of setup rules, you might behave
|
||||||
|
differently here depending on testcase->flags or
|
||||||
|
testcase->setup_data or even or testcase->name. */
|
||||||
|
|
||||||
|
/* Returning a NULL here would mean that we couldn't set up for this
|
||||||
|
test, so we don't need to test db for null. */
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
/* The clean function deallocates storage carefully and returns true on
|
||||||
|
success. */
|
||||||
|
int
|
||||||
|
clean_data_buffer(const struct testcase_t *testcase, void *ptr)
|
||||||
|
{
|
||||||
|
struct data_buffer *db = ptr;
|
||||||
|
|
||||||
|
if (db) {
|
||||||
|
free(db);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Finally, declare a testcase_setup_t with these functions. */
|
||||||
|
struct testcase_setup_t data_buffer_setup = {
|
||||||
|
setup_data_buffer, clean_data_buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Now let's write our test. */
|
||||||
|
void
|
||||||
|
test_memcpy(void *ptr)
|
||||||
|
{
|
||||||
|
/* This time, we use the argument. */
|
||||||
|
struct data_buffer *db = ptr;
|
||||||
|
|
||||||
|
/* We'll also introduce a local variable that might need cleaning up. */
|
||||||
|
char *mem = NULL;
|
||||||
|
|
||||||
|
/* Let's make sure that memcpy does what we'd like. */
|
||||||
|
strcpy(db->buffer1, "String 0");
|
||||||
|
memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
|
||||||
|
tt_str_op(db->buffer1, ==, db->buffer2);
|
||||||
|
|
||||||
|
/* Now we've allocated memory that's referenced by a local variable.
|
||||||
|
The end block of the function will clean it up. */
|
||||||
|
mem = strdup("Hello world.");
|
||||||
|
tt_assert(mem);
|
||||||
|
|
||||||
|
/* Another rather trivial test. */
|
||||||
|
tt_str_op(db->buffer1, !=, mem);
|
||||||
|
|
||||||
|
end:
|
||||||
|
/* This time our end block has something to do. */
|
||||||
|
if (mem)
|
||||||
|
free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================ */
|
||||||
|
|
||||||
|
/* Now we need to make sure that our tests get invoked. First, you take
|
||||||
|
a bunch of related tests and put them into an array of struct testcase_t.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct testcase_t demo_tests[] = {
|
||||||
|
/* Here's a really simple test: it has a name you can refer to it
|
||||||
|
with, and a function to invoke it. */
|
||||||
|
{ "strcmp", test_strcmp, },
|
||||||
|
|
||||||
|
/* The second test has a flag, "TT_FORK", to make it run in a
|
||||||
|
subprocess, and a pointer to the testcase_setup_t that configures
|
||||||
|
its environment. */
|
||||||
|
{ "memcpy", test_memcpy, TT_FORK, &data_buffer_setup },
|
||||||
|
|
||||||
|
/* The array has to end with END_OF_TESTCASES. */
|
||||||
|
END_OF_TESTCASES
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Next, we make an array of testgroups. This is mandatory. Unlike more
|
||||||
|
heavy-duty testing frameworks, groups can't next. */
|
||||||
|
struct testgroup_t groups[] = {
|
||||||
|
|
||||||
|
/* Every group has a 'prefix', and an array of tests. That's it. */
|
||||||
|
{ "demo/", demo_tests },
|
||||||
|
|
||||||
|
END_OF_GROUPS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int c, const char **v)
|
||||||
|
{
|
||||||
|
/* Finally, just call tinytest_main(). It lets you specify verbose
|
||||||
|
or quiet output with --verbose and --quiet. You can list
|
||||||
|
specific tests:
|
||||||
|
|
||||||
|
tinytest-demo demo/memcpy
|
||||||
|
|
||||||
|
or use a ..-wildcard to select multiple tests with a common
|
||||||
|
prefix:
|
||||||
|
|
||||||
|
tinytest-demo demo/..
|
||||||
|
|
||||||
|
If you list no tests, you get them all by default, so that
|
||||||
|
"tinytest-demo" and "tinytest-demo .." mean the same thing.
|
||||||
|
|
||||||
|
*/
|
||||||
|
return tinytest_main(c, v, groups);
|
||||||
|
}
|
137
test/tinytest_macros.h
Normal file
137
test/tinytest_macros.h
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/* tinytest_macros.h -- Copyright 2009 Nick Mathewson
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TINYTEST_MACROS_H
|
||||||
|
#define _TINYTEST_MACROS_H
|
||||||
|
|
||||||
|
/* Helpers for defining statement-like macros */
|
||||||
|
#define TT_STMT_BEGIN do {
|
||||||
|
#define TT_STMT_END } while(0)
|
||||||
|
|
||||||
|
/* Redefine this if your test functions want to abort with something besides
|
||||||
|
* "goto end;" */
|
||||||
|
#ifndef TT_EXIT_TEST_FUNCTION
|
||||||
|
#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Redefine this if you want to note success/failure in some different way. */
|
||||||
|
#ifndef TT_DECLARE
|
||||||
|
#define TT_DECLARE(prefix, args) \
|
||||||
|
TT_STMT_BEGIN \
|
||||||
|
printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \
|
||||||
|
printf args ; \
|
||||||
|
TT_STMT_END
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Announce a failure. Args are parenthesized printf args. */
|
||||||
|
#define TT_GRIPE(args) TT_DECLARE("FAIL", args)
|
||||||
|
|
||||||
|
/* Announce a non-failure if we're verbose. */
|
||||||
|
#define TT_BLATHER(args) \
|
||||||
|
TT_STMT_BEGIN \
|
||||||
|
if (_tinytest_get_verbosity()>1) TT_DECLARE(" OK", args); \
|
||||||
|
TT_STMT_END
|
||||||
|
|
||||||
|
#define TT_DIE(args) \
|
||||||
|
TT_STMT_BEGIN \
|
||||||
|
_tinytest_set_test_failed(); \
|
||||||
|
TT_GRIPE(args); \
|
||||||
|
TT_EXIT_TEST_FUNCTION; \
|
||||||
|
TT_STMT_END
|
||||||
|
|
||||||
|
#define TT_FAIL(args) \
|
||||||
|
TT_STMT_BEGIN \
|
||||||
|
_tinytest_set_test_failed(); \
|
||||||
|
TT_GRIPE(args); \
|
||||||
|
TT_STMT_END
|
||||||
|
|
||||||
|
/* Fail and abort the current test for the reason in msg */
|
||||||
|
#define tt_abort_msg(msg) TT_DIE((msg))
|
||||||
|
#define tt_abort() tt_fail_msg("(Failed.)")
|
||||||
|
|
||||||
|
/* Fail but do not abort the current test for the reason in msg. */
|
||||||
|
#define tt_fail_msg(msg) TT_FAIL((msg))
|
||||||
|
#define tt_fail() tt_fail_msg("(Failed.)")
|
||||||
|
|
||||||
|
#define _tt_want(b, msg, fail) \
|
||||||
|
TT_STMT_BEGIN \
|
||||||
|
if (!(b)) { \
|
||||||
|
_tinytest_set_test_failed(); \
|
||||||
|
TT_GRIPE((msg)); \
|
||||||
|
fail; \
|
||||||
|
} else { \
|
||||||
|
TT_BLATHER((msg)); \
|
||||||
|
} \
|
||||||
|
TT_STMT_END
|
||||||
|
|
||||||
|
/* Assert b, but do not stop the test if b fails. Log msg on failure. */
|
||||||
|
#define tt_want_msg(b, msg) \
|
||||||
|
_tt_want(b, msg, );
|
||||||
|
|
||||||
|
/* Assert b and stop the test if b fails. Log msg on failure. */
|
||||||
|
#define tt_assert_msg(b, msg) \
|
||||||
|
_tt_want(b, msg, TT_EXIT_TEST_FUNCTION);
|
||||||
|
|
||||||
|
/* Assert b, but do not stop the test if b fails. */
|
||||||
|
#define tt_want(b) tt_want_msg( (b), "want("#b")")
|
||||||
|
/* Assert b, and stop the test if b fails. */
|
||||||
|
#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
|
||||||
|
|
||||||
|
#define tt_assert_test_type(a,b,str_test,type,test,fmt) \
|
||||||
|
TT_STMT_BEGIN \
|
||||||
|
type _val1 = (type)(a); \
|
||||||
|
type _val2 = (type)(b); \
|
||||||
|
if (!(test)) { \
|
||||||
|
TT_DIE(("assert(%s): "fmt" vs "fmt, \
|
||||||
|
str_test, _val1, _val2)); \
|
||||||
|
} else { \
|
||||||
|
TT_BLATHER(("assert(%s): "fmt" vs "fmt, \
|
||||||
|
str_test, _val1, _val2)); \
|
||||||
|
} \
|
||||||
|
TT_STMT_END
|
||||||
|
|
||||||
|
/* Helper: assert that a op b, when cast to type. Format the values with
|
||||||
|
* printf format fmt on failure. */
|
||||||
|
#define tt_assert_op_type(a,op,b,type,fmt) \
|
||||||
|
tt_assert_test_type(a,b,#a" "#op" "#b,type,(_val1 op _val2),fmt)
|
||||||
|
|
||||||
|
#define tt_int_op(a,op,b) \
|
||||||
|
tt_assert_test_type(a,b,#a" "#op" "#b,long,(_val1 op _val2),"%ld")
|
||||||
|
|
||||||
|
#define tt_uint_op(a,op,b) \
|
||||||
|
tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
|
||||||
|
(_val1 op _val2),"%lu")
|
||||||
|
|
||||||
|
#define tt_str_op(a,op,b) \
|
||||||
|
tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
|
||||||
|
(strcmp(_val1,_val2) op 0),"<%s>")
|
||||||
|
|
||||||
|
/** Fail and log the errno as with perror. */
|
||||||
|
#define tt_fail_perror(op) \
|
||||||
|
TT_STMT_BEGIN \
|
||||||
|
TT_DIE(("%s: %s [%d]",(op),strerror(errno),errno)); \
|
||||||
|
TT_STMT_END
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user