Index: ossp-pkg/sa/Makefile.in RCS File: /v/ossp/cvs/ossp-pkg/sa/Makefile.in,v rcsdiff -q -kk '-r1.7' '-r1.8' -u '/v/ossp/cvs/ossp-pkg/sa/Makefile.in,v' 2>/dev/null --- Makefile.in 2001/10/08 15:01:26 1.7 +++ Makefile.in 2001/10/10 15:01:56 1.8 @@ -51,7 +51,7 @@ LIB_OBJS = sa.lo TST_NAME = sa_test -TST_OBJS = sa_test.o +TST_OBJS = sa_test.o ts.o .SUFFIXES: .SUFFIXES: .c .o .lo @@ -59,7 +59,7 @@ all: $(LIB_NAME) $(TST_NAME) .c.o: - @$(CC) $(CPPFLAGS) $(CFLAGS) -c $< + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< .c.lo: @$(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS) -c $< Index: ossp-pkg/sa/sa_test.c RCS File: /v/ossp/cvs/ossp-pkg/sa/sa_test.c,v rcsdiff -q -kk '-r1.7' '-r1.8' -u '/v/ossp/cvs/ossp-pkg/sa/sa_test.c,v' 2>/dev/null --- sa_test.c 2001/10/08 15:08:46 1.7 +++ sa_test.c 2001/10/10 15:01:56 1.8 @@ -35,90 +35,50 @@ #include #include +#include "ts.h" #include "sa.h" -#define DIE_MARK \ - __FILE__, __LINE__ - -static void die(const char *file, int line, char *fmt, ...) +TST_FUNC(test_sa) { - va_list ap; +} - va_start(ap, fmt); - fprintf(stderr, "%s:%d:ERROR: ", file, line); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(1); +TST_FUNC(test_saa) +{ + sa_addr_t *saa; + sa_rc_t rv; + char *cp1; + char *cp2; + + tst_check(TST, "sa_addr_create"); + if ((rv = sa_addr_create(&saa)) != SA_OK) + tst_fail(tst, "rv=%d (%s)", rv, sa_error(rv)); + + tst_check(TST, "sa_addr_u2a"); + cp1 = "inet://127.0.0.1:12345"; + if ((rv = sa_addr_u2a(saa, cp1)) != SA_OK) + tst_fail(TST, "rv=%d (%s)", rv, sa_error(rv)); + + tst_check(TST, "sa_addr_a2u"); + if ((rv = sa_addr_a2u(saa, &cp2)) != SA_OK) + tst_fail(TST, "rv=%d (%s)", rv, sa_error(rv)); + if (strcmp(cp1, cp2) != 0) + tst_fail(TST, "import \"%s\" <-> export \"%s\"", cp1, cp2); + + tst_check(tst, "sa_addr_destroy"); + if ((rv = sa_addr_destroy(saa)) != SA_OK) + tst_fail(TST, "rv=%d (%s)", rv, sa_error(rv)); } -int main(int argc, char *argv[]) +int main(int argc, char *argv[]) { - sa_addr_t *ra; - sa_addr_t *la; - sa_t *sa; - char caBuf[1024]; - int nBuf; - char caTime[15+1]; - time_t now; - struct tm *tm; - struct utsname uts; - char *cp; - char caTag[32+1]; - char *cpHost; + ts_t *ts; int n; - /* create remote address */ - if (sa_addr_create(&ra) != SA_OK) - die(DIE_MARK, "sa_addr_create (ra)"); - if (sa_addr_u2a(ra, "inet://141.1.129.1:514") != SA_OK) - die(DIE_MARK, "sa_addr_u2a (ra)"); - - /* create local address */ - if (sa_addr_create(&la) != SA_OK) - die(DIE_MARK, "sa_addr_create (la)"); - if (sa_addr_u2a(la, "inet://0.0.0.0:0") != SA_OK) - die(DIE_MARK, "sa_addr_u2a (la)"); - - /* create datagram socket */ - if (sa_create(&sa) != SA_OK) - die(DIE_MARK, "sa_create"); - if (sa_type(sa, SA_TYPE_DATAGRAM) != SA_OK) - die(DIE_MARK, "sa_type"); - - /* bind socket to local address */ - if (sa_bind(sa, la) != SA_OK) - die(DIE_MARK, "sa_bind"); - - /* RFC3164: The BSD syslog Protocol; C. Lonvick; August 2001. */ - now = time(NULL); - tm = localtime(&now); - strftime(caTime, sizeof(caTime), "%b %e %H:%M:%S", tm); - if (uname(&uts) == -1) - die(DIE_MARK, "uname"); - cpHost = strdup(uts.nodename); - if ((cp = strchr(cpHost, '.')) != NULL) - *cp = '\0'; - strcpy(caTag, "progname[12]: "); - if (strlen(caTag) > 32) - caTag[32] = '\0'; - sprintf(caBuf, "<16>%s %s %s[%ld]: %s", caTime, cpHost, - argv[0], (long)getpid(), "test for Internet Datagram socket"); - fprintf(stderr, "Send to syslog: \"%s\"\n", caBuf); - - /* send message to syslogd(8) */ - nBuf = strlen(caBuf); - if (sa_send(sa, caBuf, nBuf, (size_t *)&n, ra) != SA_OK) - die(DIE_MARK, "sa_writeto"); - - /* destroy socket and address objects */ - if (sa_destroy(sa) != SA_OK) - die(DIE_MARK, "sa_destroy"); - if (sa_addr_destroy(la) != SA_OK) - die(DIE_MARK, "sa_addr_destroy (la)"); - if (sa_addr_destroy(ra) != SA_OK) - die(DIE_MARK, "sa_addr_destroy (ra)"); - - return 0; + ts = ts_new("OSSP SA (Socket Abstraction Library)"); + ts_test(ts, test_saa, "socket address abstraction"); + ts_test(ts, test_sa, "socket abstraction"); + n = ts_run(ts); + ts_free(ts); + return n; } Index: ossp-pkg/sa/ts.c RCS File: /v/ossp/cvs/ossp-pkg/sa/ts.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/sa/ts.c,v' | diff -u /dev/null - -L'ossp-pkg/sa/ts.c' 2>/dev/null --- ossp-pkg/sa/ts.c +++ - 2024-04-27 00:31:54.362667697 +0200 @@ -0,0 +1,463 @@ +/* +** TS - OSSP Test Suite Library +** Copyright (c) 2001 Ralf S. Engelschall +** Copyright (c) 2001 The OSSP Project +** Copyright (c) 2001 Cable & Wireless Deutschland +** +** This file is part of OSSP TS, a test suite library which +** can be found at http://www.ossp.org/pkg/ts/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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. +** +** ts.c: test suite library +*/ + +#include +#include +#include +#include + +#include "ts.h" + +/* embedded ring data structure library */ +#define RING_ENTRY(elem) \ + struct { elem *next; elem *prev; } +#define RING_HEAD(elem) \ + struct { elem *next; elem *prev; } +#define RING_SENTINEL(hp, elem, link) \ + (elem *)((char *)(hp) - ((size_t)(&((elem *)0)->link))) +#define RING_FIRST(hp) \ + (hp)->next +#define RING_LAST(hp) \ + (hp)->prev +#define RING_NEXT(ep, link) \ + (ep)->link.next +#define RING_PREV(ep, link) \ + (ep)->link.prev +#define RING_INIT(hp, elem, link) \ + do { RING_FIRST((hp)) = RING_SENTINEL((hp), elem, link); \ + RING_LAST((hp)) = RING_SENTINEL((hp), elem, link); } while (0) +#define RING_EMPTY(hp, elem, link) \ + (RING_FIRST((hp)) == RING_SENTINEL((hp), elem, link)) +#define RING_ELEM_INIT(ep, link) \ + do { RING_NEXT((ep), link) = (ep); \ + RING_PREV((ep), link) = (ep); } while (0) +#define RING_SPLICE_BEFORE(lep, ep1, epN, link) \ + do { RING_NEXT((epN), link) = (lep); \ + RING_PREV((ep1), link) = RING_PREV((lep), link); \ + RING_NEXT(RING_PREV((lep), link), link) = (ep1); \ + RING_PREV((lep), link) = (epN); } while (0) +#define RING_SPLICE_TAIL(hp, ep1, epN, elem, link) \ + RING_SPLICE_BEFORE(RING_SENTINEL((hp), elem, link), (ep1), (epN), link) +#define RING_INSERT_TAIL(hp, nep, elem, link) \ + RING_SPLICE_TAIL((hp), (nep), (nep), elem, link) +#define RING_FOREACH(ep, hp, elem, link) \ + for ((ep) = RING_FIRST((hp)); \ + (ep) != RING_SENTINEL((hp), elem, link); \ + (ep) = RING_NEXT((ep), link)) + +/* test suite test log */ +struct tstl_st; +typedef struct tstl_st tstl_t; +struct tstl_st { + RING_ENTRY(tstl_t) next; + char *text; + const char *file; + int line; +}; + +/* test suite test check */ +struct tstc_st; +typedef struct tstc_st tstc_t; +struct tstc_st { + RING_ENTRY(tstc_t) next; + char *title; + int failed; + const char *file; + int line; + RING_HEAD(tstl_t) logs; +}; + +/* test suite test */ +struct tst_st { + RING_ENTRY(tst_t) next; + char *title; + tst_func_t func; + const char *file; + int line; + RING_HEAD(tstc_t) checks; +}; + +/* test suite */ +struct ts_st { + char *title; + RING_HEAD(tst_t) tests; +}; + +/* minimal output-independent vprintf(3) variant which supports %{c,s,d,%} only */ +static int ts_mvxprintf(char *buffer, size_t bufsize, const char *format, va_list ap) +{ + /* sufficient integer buffer: x log_10(2) + safety */ + char ibuf[((sizeof(int)*8)/3)+10]; + char *cp; + char c; + int d; + int n; + int bytes; + + if (format == NULL || ap == NULL) + return -1; + bytes = 0; + while (*format != '\0') { + if (*format == '%') { + c = *(format+1); + if (c == '%') { + /* expand "%%" */ + cp = &c; + n = sizeof(char); + } + else if (c == 'c') { + /* expand "%c" */ + c = (char)va_arg(ap, int); + cp = &c; + n = sizeof(char); + } + else if (c == 's') { + /* expand "%s" */ + if ((cp = (char *)va_arg(ap, char *)) == NULL) + cp = "(null)"; + n = strlen(cp); + } + else if (c == 'd') { + /* expand "%d" */ + d = (int)va_arg(ap, int); +#ifdef HAVE_SNPRINTF + snprintf(ibuf, sizeof(ibuf), "%d", d); /* explicitly secure */ +#else + sprintf(ibuf, "%d", d); /* implicitly secure */ +#endif + cp = ibuf; + n = strlen(cp); + } + else { + /* any other "%X" */ + cp = (char *)format; + n = 2; + } + format += 2; + } + else { + /* plain text */ + cp = (char *)format; + if ((format = strchr(cp, '%')) == NULL) + format = strchr(cp, '\0'); + n = format - cp; + } + /* perform output operation */ + if (buffer != NULL) { + if (n > bufsize) + return -1; + memcpy(buffer, cp, n); + buffer += n; + bufsize -= n; + } + bytes += n; + } + /* nul-terminate output */ + if (buffer != NULL) { + if (bufsize == 0) + return -1; + *buffer = '\0'; + } + return bytes; +} + +/* minimal vasprintf(3) variant which supports %{c,s,d} only */ +static char *ts_mvasprintf(const char *format, va_list ap) +{ + char *buffer; + int n; + va_list ap2; + + if (format == NULL || ap == NULL) + return NULL; + ap2 = ap; + if ((n = ts_mvxprintf(NULL, 0, format, ap)) == -1) + return NULL; + if ((buffer = (char *)malloc(n+1)) == NULL) + return NULL; + ts_mvxprintf(buffer, n+1, format, ap2); + return buffer; +} + +/* minimal asprintf(3) variant which supports %{c,s,d} only */ +static char *ts_masprintf(const char *format, ...) +{ + va_list ap; + char *cp; + + va_start(ap, format); + cp = ts_mvasprintf(format, ap); + va_end(ap); + return cp; +} + +/* create test suite */ +ts_t *ts_new(const char *fmt, ...) +{ + ts_t *ts; + va_list ap; + + if ((ts = (ts_t *)malloc(sizeof(ts_t))) == NULL) + return NULL; + va_start(ap, fmt); + ts->title = ts_mvasprintf(fmt, ap); + RING_INIT(&ts->tests, tst_t, next); + va_end(ap); + return ts; +} + +/* add test case to test suite */ +void ts_test(ts_t *ts, tst_func_t func, const char *fmt, ...) +{ + tst_t *tst; + va_list ap; + + if (ts == NULL || func == NULL || fmt == NULL) + return; + if ((tst = (tst_t *)malloc(sizeof(tst_t))) == NULL) + return; + RING_ELEM_INIT(tst, next); + va_start(ap, fmt); + tst->title = ts_mvasprintf(fmt, ap); + va_end(ap); + tst->func = func; + tst->file = NULL; + tst->line = 0; + RING_INIT(&tst->checks, tstc_t, next); + RING_INSERT_TAIL(&ts->tests, tst, tst_t, next); + return; +} + +/* run test suite */ +int ts_run(ts_t *ts) +{ + tst_t *tst; + tstc_t *tstc; + tstl_t *tstl; + int total_tests, total_tests_failed; + int total_checks, total_checks_failed; + int test_checks, test_checks_failed; + const char *file; + int line; + char *cp; + + if (ts == NULL) + return 0; + + /* init total counters */ + total_tests = 0; + total_tests_failed = 0; + total_checks = 0; + total_checks_failed = 0; + + fprintf(stdout, "\n"); + fprintf(stdout, " Test Suite: %s\n", ts->title); + fprintf(stdout, " __________________________________________________________________\n"); + fprintf(stdout, "\n"); + fflush(stdout); + + /* iterate through all test cases */ + RING_FOREACH(tst, &ts->tests, tst_t, next) { + cp = ts_masprintf(" Test: %s ........................................" + "........................................", tst->title); + cp[60] = '\0'; + fprintf(stdout, "%s", cp); + free(cp); + fflush(stdout); + + /* init test case counters */ + test_checks = 0; + test_checks_failed = 0; + + /* run the test case function */ + tst->func(tst); + + /* iterate through all performed checks to determine status */ + RING_FOREACH(tstc, &tst->checks, tstc_t, next) { + test_checks++; + if (tstc->failed) + test_checks_failed++; + } + + if (test_checks_failed > 0) { + /* some checks failed, so do detailed reporting of test case */ + fprintf(stdout, " FAILED\n"); + fprintf(stdout, " Ops, %d/%d checks failed! Detailed report follows:\n", + test_checks_failed, test_checks); + RING_FOREACH(tstc, &tst->checks, tstc_t, next) { + file = (tstc->file != NULL ? tstc->file : tst->file); + line = (tstc->line != 0 ? tstc->line : tst->line); + if (file != NULL) + fprintf(stdout, " Check: %sX [%s:%d]\n", tstc->title, file, line); + else + fprintf(stdout, " Check: %s\n", tstc->title); + RING_FOREACH(tstl, &tstc->logs, tstl_t, next) { + file = (tstl->file != NULL ? tstl->file : file); + line = (tstl->line != 0 ? tstl->line : line); + if (file != NULL) + fprintf(stdout, " Log: %s [%s:%d]\n", tstl->text, file, line); + else + fprintf(stdout, " Log: %s\n", tstl->text); + } + } + } + else { + /* test case ran successfully */ + fprintf(stdout, ".... OK\n"); + } + fflush(stdout); + + /* accumulate counters */ + total_checks += test_checks; + total_tests++; + if (test_checks_failed > 0) { + total_checks_failed += test_checks_failed; + total_tests_failed++; + } + } + + /* print test suite summary */ + fprintf(stdout, " __________________________________________________________________\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " Test Summary: %d tests (%d ok, %d failed), %d checks (%d ok, %d failed)\n", + total_tests, (total_tests - total_tests_failed), total_tests_failed, + total_checks, (total_checks - total_checks_failed), total_checks_failed); + if (total_tests_failed > 0) + fprintf(stdout, " Test Suite: FAILED (Test Suite Failed)\n"); + else + fprintf(stdout, " Test Suite: OK (Test Suite Passed Successfully)\n"); + fprintf(stdout, "\n"); + fflush(stdout); + + return total_checks_failed; +} + +/* destroy test suite */ +void ts_free(ts_t *ts) +{ + tst_t *tst; + tstc_t *tstc; + tstl_t *tstl; + + if (ts == NULL) + return; + RING_FOREACH(tst, &ts->tests, tst_t, next) { + RING_FOREACH(tstc, &tst->checks, tstc_t, next) { + RING_FOREACH(tstl, &tstc->logs, tstl_t, next) { + free(tstl->text); + } + free(tstc->title); + free(tstc); + } + free(tst->title); + free(tst); + } + free(tst->title); + free(ts); + return; +} + +/* annotate test case with file name and line number */ +tst_t *tst_ctx(tst_t *tst, const char *file, int line) +{ + if (tst != NULL && file != NULL) { + tst->file = file; + tst->line = line; + } + return tst; +} + +/* annotate test case with check */ +void tst_check(tst_t *tst, const char *fmt, ...) +{ + tstc_t *tstc; + va_list ap; + + if (tst == NULL || fmt == NULL) + return; + if ((tstc = (tstc_t *)malloc(sizeof(tstc_t))) == NULL) + return; + va_start(ap, fmt); + RING_ELEM_INIT(tstc, next); + tstc->title = ts_mvasprintf(fmt, ap); + tstc->failed = 0; + tstc->file = tst->file; + tstc->line = tst->line; + RING_INIT(&tstc->logs, tstl_t, next); + RING_INSERT_TAIL(&tst->checks, tstc, tstc_t, next); + va_end(ap); + return; +} + +/* annotate test case with log message and failure */ +void tst_fail(tst_t *tst, const char *fmt, ...) +{ + tstc_t *tstc; + tstl_t *tstl; + va_list ap; + + if (tst == NULL || fmt == NULL) + return; + if ((tstl = (tstl_t *)malloc(sizeof(tstl_t))) == NULL) + return; + va_start(ap, fmt); + tstl->text = ts_mvasprintf(fmt, ap); + tstl->file = tst->file; + tstl->line = tst->line; + RING_ELEM_INIT(tstl, next); + tstc = RING_LAST(&tst->checks); + RING_INSERT_TAIL(&tstc->logs, tstl, tstl_t, next); + tstc->failed = 1; + va_end(ap); + return; +} + +/* annotate test case with log message only */ +void tst_log(tst_t *tst, const char *fmt, ...) +{ + tstc_t *tstc; + tstl_t *tstl; + va_list ap; + + if (tst == NULL || fmt == NULL) + return; + if ((tstl = (tstl_t *)malloc(sizeof(tstl_t))) == NULL) + return; + va_start(ap, fmt); + tstl->text = ts_mvasprintf(fmt, ap); + tstl->file = tst->file; + tstl->line = tst->line; + RING_ELEM_INIT(tstl, next); + tstc = RING_LAST(&tst->checks); + RING_INSERT_TAIL(&tstc->logs, tstl, tstl_t, next); + va_end(ap); + return; +} + Index: ossp-pkg/sa/ts.h RCS File: /v/ossp/cvs/ossp-pkg/sa/ts.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/sa/ts.h,v' | diff -u /dev/null - -L'ossp-pkg/sa/ts.h' 2>/dev/null --- ossp-pkg/sa/ts.h +++ - 2024-04-27 00:31:54.365481941 +0200 @@ -0,0 +1,62 @@ +/* +** TS - OSSP Test Suite Library +** Copyright (c) 2001 Ralf S. Engelschall +** Copyright (c) 2001 The OSSP Project +** Copyright (c) 2001 Cable & Wireless Deutschland +** +** This file is part of OSSP TS, a test suite library which +** can be found at http://www.ossp.org/pkg/ts/. +** +** Permission to use, copy, modify, and distribute this software for +** any purpose with or without fee is hereby granted, provided that +** the above copyright notice and this permission notice appear in all +** copies. +** +** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR +** CONTRIBUTORS 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. +** +** ts.h: test suite library API +*/ + +#ifndef _TS_H_ +#define _TS_H_ + +struct ts_st; +typedef struct ts_st ts_t; + +struct tst_st; +typedef struct tst_st tst_t; + +typedef void (*tst_func_t)(tst_t *); + +#define TST_FUNC(name) \ + static void name(tst_t *tst) + +#define TST_CTX(tst) \ + tst_ctx(tst, __FILE__, __LINE__) + +#define TST \ + TST_CTX(tst) + +ts_t *ts_new (const char *fmt, ...); +void ts_test (ts_t *ts, tst_func_t func, const char *fmt, ...); +int ts_run (ts_t *ts); +void ts_free (ts_t *ts); + +tst_t *tst_ctx (tst_t *tst, const char *file, int line); +void tst_check (tst_t *tst, const char *fmt, ...); +void tst_fail (tst_t *tst, const char *fmt, ...); +void tst_log (tst_t *tst, const char *fmt, ...); + +#endif /* _TS_H_ */ +