Index: ossp-pkg/str/.cvsignore RCS File: /v/ossp/cvs/ossp-pkg/str/.cvsignore,v rcsdiff -q -kk '-r1.12' '-r1.13' -u '/v/ossp/cvs/ossp-pkg/str/.cvsignore,v' 2>/dev/null --- .cvsignore 2002/01/24 16:30:04 1.12 +++ .cvsignore 2002/04/01 09:03:49 1.13 @@ -1,26 +1,25 @@ -Makefile -config.log -config.cache -config.status -str-config -str_config.h -str_config.h.in -str_test *.core -*.lo *.la +*.lo .libs -libtool -str_pcre_gen -str_pcre_tab.c +Makefile +config.cache config.guess +config.h +config.h.in +config.log +config.status config.sub configure +libtool libtool.m4 ltmain.sh shtool -str.3 +str-config str-config.1 +str.3 str.h str_pcre.tab -config.h.in +str_pcre_gen +str_pcre_tab.c +str_test Index: ossp-pkg/str/Makefile.in RCS File: /v/ossp/cvs/ossp-pkg/str/Makefile.in,v rcsdiff -q -kk '-r1.44' '-r1.45' -u '/v/ossp/cvs/ossp-pkg/str/Makefile.in,v' 2>/dev/null --- Makefile.in 2002/04/01 08:32:54 1.44 +++ Makefile.in 2002/04/01 09:03:49 1.45 @@ -104,8 +104,8 @@ $(LIBTOOL) --mode=link --quiet $(CC) -o libstr.la $(OBJS) -rpath $(libdir) \ -version-info `$(SHTOOL) version -l c -d libtool str_version.c` -str_test: str_test.o libstr.la - $(LIBTOOL) --mode=link --quiet $(CC) $(LDFLAGS) -o str_test str_test.o libstr.la $(LIBS) +str_test: str_test.o ts.o libstr.la + $(LIBTOOL) --mode=link --quiet $(CC) $(LDFLAGS) -o str_test str_test.o ts.o libstr.la $(LIBS) str-config.1: str-config.pod $(_VERSION_FILE) BASENAME="str-config"; SEC=1; \ @@ -116,7 +116,6 @@ NAME="Str"; ONELINE="String Library"; \ $(_MANPAGE) - str_pcre.lo: str_pcre.tab str_pcre.c str_pcre.tab: str_pcre.c $(CC) $(CFLAGS) -DSTR_PCRE_TAB $(LDFLAGS) -o str_pcre.gen str_pcre.c $(LIBS) @@ -147,7 +146,7 @@ distclean: clean $(RM) str-config - $(RM) str_config.h + $(RM) config.h $(RM) str_pcre.tab $(RM) config.log config.cache config.status $(RM) libtool @@ -156,7 +155,7 @@ realclean: distclean $(RM) config.guess config.sub ltmain.sh libtool.m4 - $(RM) configure str_config.h.in + $(RM) configure config.h.in $(RM) str-config.1 str.3 $(RM) shtool Index: ossp-pkg/str/configure.ac RCS File: /v/ossp/cvs/ossp-pkg/str/configure.ac,v rcsdiff -q -kk '-r1.10' '-r1.11' -u '/v/ossp/cvs/ossp-pkg/str/configure.ac,v' 2>/dev/null --- configure.ac 2002/04/01 08:32:54 1.10 +++ configure.ac 2002/04/01 09:03:49 1.11 @@ -34,7 +34,7 @@ AC_CHECK_EXTLIB([Dmalloc], dmalloc, dmalloc_debug, dmalloc.h, [AC_DEFINE(WITH_DMALLOC, 1, [Define to 1 if building with Dmalloc])]) -AC_CONFIG_HEADERS(str_config.h) +AC_CONFIG_HEADERS(config.h) AC_CONFIG_FILES([Makefile str.h str-config]) AC_CONFIG_COMMANDS([adjustment], [chmod a+x str-config]) AC_OUTPUT Index: ossp-pkg/str/str_p.h RCS File: /v/ossp/cvs/ossp-pkg/str/str_p.h,v rcsdiff -q -kk '-r1.19' '-r1.20' -u '/v/ossp/cvs/ossp-pkg/str/str_p.h,v' 2>/dev/null --- str_p.h 2002/04/01 08:32:54 1.19 +++ str_p.h 2002/04/01 09:03:49 1.20 @@ -30,13 +30,15 @@ #ifndef _STR_P_H_ #define _STR_P_H_ -#include "str.h" -#include "str_config.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include /* for malloc, etc. */ #include /* for modf(3) */ #include /* ... */ +#include "str.h" #include "str_pcre.h" #if defined(HAVE_DMALLOC_H) && defined(WITH_DMALLOC) Index: ossp-pkg/str/str_test.c RCS File: /v/ossp/cvs/ossp-pkg/str/str_test.c,v rcsdiff -q -kk '-r1.24' '-r1.25' -u '/v/ossp/cvs/ossp-pkg/str/str_test.c,v' 2>/dev/null --- str_test.c 2002/04/01 08:32:54 1.24 +++ str_test.c 2002/04/01 09:03:49 1.25 @@ -30,40 +30,40 @@ #include #include -#include "str.h" -#include "str_config.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #if defined(HAVE_DMALLOC_H) && defined(WITH_DMALLOC) #include "dmalloc.h" #endif +#include "str.h" +#include "ts.h" + #define LONG_STRING 1024 /* * Test String Length */ -static void test_length(int *ok, int *fail) +TS_TEST(test_length) { - if (str_len(NULL) == 0) - (*ok)++; - else - (*fail)++; - - if (str_len("") == 0) - (*ok)++; - else - (*fail)++; - - if (str_len("a") == 1) - (*ok)++; - else - (*fail)++; - - if (str_len("foo bar quux") == 12) - (*ok)++; - else - (*fail)++; + ts_test_check(TS_CTX, "NULL handling"); + if (str_len(NULL) != 0) + ts_test_fail(TS_CTX, "unexpected non-zero return"); + + ts_test_check(TS_CTX, "empty string handling"); + if (str_len("") != 0) + ts_test_fail(TS_CTX, "unexpected non-zero return"); + + ts_test_check(TS_CTX, "short string handling"); + if (str_len("a") != 1) + ts_test_fail(TS_CTX, "unexpected return != 1"); + + ts_test_check(TS_CTX, "longer string handling"); + if (str_len("foo bar quux") != 12) + ts_test_fail(TS_CTX, "unexpected return != 12"); return; } @@ -87,22 +87,18 @@ { NULL, 0, NULL, 0 } }; -static void test_locate(int *ok, int *fail) +TS_TEST(test_locate) { int i; char *rv; for (i = 0; loctab[i].s != NULL; i++) { rv = str_locate(loctab[i].s, loctab[i].n, loctab[i].p); - printf("str_locate(\"%s\", %d, \"%s\") = \"%s\"\n", - loctab[i].s, loctab[i].n, loctab[i].p, rv == NULL ? "[NULL]" : rv); - if ((rv-loctab[i].s == loctab[i].o) || (rv == NULL && loctab[i].o == -1)) - (*ok)++; - else { - fprintf(stderr, "ERROR: result was \"%s\", expected \"%s\"\n", - rv, loctab[i].s+loctab[i].o); - (*fail)++; - } + ts_test_check(TS_CTX, "str_locate(\"%s\", %d, \"%s\") = \"%s\"", + loctab[i].s, loctab[i].n, loctab[i].p, rv == NULL ? "[NULL]" : rv); + if (!((rv-loctab[i].s == loctab[i].o) || (rv == NULL && loctab[i].o == -1))) + ts_test_fail(TS_CTX, "result was \"%s\", expected \"%s\"", + rv, loctab[i].s+loctab[i].o); } return; } @@ -129,22 +125,18 @@ { NULL, 0, NULL, 0, 0 } }; -static void test_span(int *ok, int *fail) +TS_TEST(test_span) { int i; char *rv; for (i = 0; spantab[i].s != NULL; i++) { rv = str_span(spantab[i].s, spantab[i].n, spantab[i].cs, spantab[i].m); - printf("str_span(\"%s\", %d, \"%s\", %d) = \"%s\"\n", - spantab[i].s, spantab[i].n, spantab[i].cs, spantab[i].m, rv); - if (rv-spantab[i].s == spantab[i].o) - (*ok)++; - else { - fprintf(stderr, "ERROR: result was \"%s\", expected \"%s\"\n", - rv, spantab[i].s+spantab[i].o); - (*fail)++; - } + ts_test_check(TS_CTX, "str_span(\"%s\", %d, \"%s\", %d) = \"%s\"", + spantab[i].s, spantab[i].n, spantab[i].cs, spantab[i].m, rv); + if (rv-spantab[i].s != spantab[i].o) + ts_test_fail(TS_CTX, "result was \"%s\", expected \"%s\"", + rv, spantab[i].s+spantab[i].o); } return; } @@ -198,7 +190,7 @@ return; } -static void test_tokenize(int *ok, int *fail) +TS_TEST(test_tokenize) { char *cp; char *cp2; @@ -207,23 +199,24 @@ int i, j; for (i = 0; toktab[i].s != NULL; i++) { - fprintf(stderr, "Testing tokenization of %s\n", prstr(toktab[i].s)), prstr_free(); + ts_test_check(TS_CTX, "tokenization of \"%s\"\n", prstr(toktab[i].s)); + prstr_free(); cp2 = cp = strdup(toktab[i].s); for (j = 0; j < 4; j++) { cp3 = strdup(cp); rc = str_token(&cp, toktab[i].d, toktab[i].q, toktab[i].c, toktab[i].f); - fprintf(stderr, "str_token(&%s, %s, %s, %s, %d) = %s\n", - prstr(cp3), prstr(toktab[i].d), - prstr(toktab[i].q), prstr(toktab[i].c), - toktab[i].f, prstr(rc)), prstr_free(); + ts_test_check(TS_CTX, "str_token(&%s, %s, %s, %s, %d) = %s", + prstr(cp3), prstr(toktab[i].d), + prstr(toktab[i].q), prstr(toktab[i].c), + toktab[i].f, prstr(rc)), prstr_free(); free(cp3); if (!( (rc == NULL && toktab[i].r[j] == NULL) || (rc != NULL && toktab[i].r[j] != NULL && strcmp(rc, toktab[i].r[j]) == 0))) { - fprintf(stderr, "ERROR: expected result is %s\n", prstr(toktab[i].r[j])), prstr_free(); + ts_test_fail(TS_CTX, "expected result is \"%s\"", prstr(toktab[i].r[j])); + prstr_free(); } } free(cp2); - fprintf(stderr, "\n"); } return; } @@ -253,14 +246,14 @@ { NULL, NULL, NULL, NULL, NULL, NULL, 0 } }; -static void test_parsing(int *ok, int *fail) +TS_TEST(test_parsing) { int i; int rv; char *r1, *r2, *r3, *r4; for (i = 0; test2_tab[i].s != NULL; i++) { - fprintf(stderr, "%d. str_parse(\"%s\", \"%s\", ...)\n", i, test2_tab[i].s, test2_tab[i].p); + ts_test_check(TS_CTX, "str_parse(\"%s\", \"%s\", ...)", test2_tab[i].s, test2_tab[i].p); if (*(test2_tab[i].p) == 's') { r1 = NULL; r2 = test2_tab[i].r2; @@ -272,10 +265,6 @@ r1 = r2 = r3 = r4 = NULL; rv = str_parse(test2_tab[i].s, test2_tab[i].p, &r1, &r2, &r3, &r4); } - fprintf(stderr, "%d. str_parse(\"%s\", \"%s\", ...) = %d + <%s><%s><%s><%s>\n", - i, test2_tab[i].s, test2_tab[i].p, rv, - r1 == NULL ? "NULL" : r1, r2 == NULL ? "NULL" : r2, - r3 == NULL ? "NULL" : r3, r4 == NULL ? "NULL" : r4); if (rv != test2_tab[i].rv || ((r1 == NULL && test2_tab[i].r1 != NULL) || (r1 != NULL && test2_tab[i].r1 == NULL) || @@ -289,16 +278,13 @@ ((r4 == NULL && test2_tab[i].r4 != NULL) || (r4 != NULL && test2_tab[i].r4 == NULL) || (r4 != NULL && test2_tab[i].r4 != NULL && strcmp(r4, test2_tab[i].r4) != 0))) { - fprintf(stderr, " ERROR: expected result: %d + <%s><%s><%s><%s>\n", - test2_tab[i].rv, - test2_tab[i].r1 == NULL ? "NULL" : test2_tab[i].r1, - test2_tab[i].r2 == NULL ? "NULL" : test2_tab[i].r2, - test2_tab[i].r3 == NULL ? "NULL" : test2_tab[i].r3, - test2_tab[i].r4 == NULL ? "NULL" : test2_tab[i].r4); - (*fail)++; + ts_test_fail(TS_CTX, "expected result: %d + <%s><%s><%s><%s>", + test2_tab[i].rv, + test2_tab[i].r1 == NULL ? "NULL" : test2_tab[i].r1, + test2_tab[i].r2 == NULL ? "NULL" : test2_tab[i].r2, + test2_tab[i].r3 == NULL ? "NULL" : test2_tab[i].r3, + test2_tab[i].r4 == NULL ? "NULL" : test2_tab[i].r4); } - else - (*ok)++; } str_parse(NULL, NULL); return; @@ -308,7 +294,7 @@ * Test String Formatting */ -static void test_formatting(int *ok, int *fail) +TS_TEST(test_formatting) { char buf1[LONG_STRING]; char buf2[LONG_STRING]; @@ -347,160 +333,102 @@ int x, y; int len; - fprintf(stderr, "\n** Testing str_format format codes against vendor sprintf **\n\n"); + ts_test_check(TS_CTX, "str_format vs. vendor sprintf comparison"); for (x = 0; fp_fmt[x] != NULL; x++) { - fprintf(stderr, "testing \"%s\"\n", fp_fmt[x]); + ts_test_check(TS_CTX, "str_format(..,..,\"%s\",..)", fp_fmt[x]); for (y = 0; fp_nums[y] != 0; y++) { len = str_format(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); sprintf(buf2, fp_fmt[x], fp_nums[y]); - if (strcmp(buf1, buf2) != 0) { - fprintf(stderr, " mismatch:\n"); - fprintf(stderr, " str_format: \"%s\"\n" - " sprintf: \"%s\"\n", buf1, buf2); - (*fail)++; - } - else { - fprintf(stderr, " ok: %d \"%s\" (%d)\n", len, buf1, (int)strlen(buf1)); - (*ok)++; - } + if (strcmp(buf1, buf2) != 0) + ts_test_fail(TS_CTX, "mismatch: str_format: \"%s\", snprintf: \"%s\"", buf1, buf2); } } for (x = 0; int_fmt[x] != NULL; x++) { - fprintf(stderr, "testing \"%s\"\n", int_fmt[x]); + ts_test_check(TS_CTX, "str_format(..,..,\"%s\",..)", int_fmt[x]); for (y = 0; int_nums[y] != 0; y++) { len = str_format(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); sprintf(buf2, int_fmt[x], int_nums[y]); - if (strcmp(buf1, buf2) != 0) { - fprintf(stderr, " mismatch:\n"); - fprintf(stderr, " str_format: \"%s\"\n" - " sprintf: \"%s\"\n", buf1, buf2); - (*fail)++; - } - else { - fprintf(stderr, " ok: %d \"%s\" (%d)\n", len, buf1, (int)strlen(buf1)); - (*ok)++; - } + if (strcmp(buf1, buf2) != 0) + ts_test_fail(TS_CTX, "mismatch: str_format: \"%s\", snprintf: \"%s\"", buf1, buf2); } } return; } -static void test_base64_do(unsigned char *ucp, int ulen, int mode, int *ok, int *fail) +/* + * Test Base64 Encoding/Decoding + */ + +static void test_base64_do(ts_test_t *_t, unsigned char *ucp, int ulen, int mode) { unsigned char ucp2[1024]; char cp[1024]; int n1, n2, n3, n4; int i; - int fine; n1 = str_base64(NULL, 0, ucp, ulen, STR_BASE64_ENCODE|mode); n2 = str_base64(cp, sizeof(cp), ucp, ulen, STR_BASE64_ENCODE|mode); - if (n1 != n2) { - fprintf(stderr, " ERROR: encoding length mismatch: %d vs. %d\n", n1, n2); - (*fail)++; - } - else - (*ok)++; + if (n1 != n2) + ts_test_fail(TS_CTX, "encoding length mismatch: %d vs. %d\n", n1, n2); n3 = str_base64(cp, n2, NULL, 0, STR_BASE64_DECODE|mode); - if (n3 != ulen) { - fprintf(stderr, " ERROR: decoding check length mismatch: %d vs. %d\n", n3, ulen); - (*fail)++; - } - else - (*ok)++; + if (n3 != ulen) + ts_test_fail(TS_CTX, "decoding check length mismatch: %d vs. %d\n", n3, ulen); n4 = str_base64(cp, n2, ucp2, ulen, STR_BASE64_DECODE|mode); - if (n3 != n4) { - fprintf(stderr, " ERROR: decoding length mismatch: %d vs. %d\n", n3, n4); - (*fail)++; - } - else - (*ok)++; - fine = TRUE; + if (n3 != n4) + ts_test_fail(TS_CTX, "decoding length mismatch: %d vs. %d\n", n3, n4); for (i = 0; i < 256; i++) { if (ucp[i] != ucp2[i]) { - fine = FALSE; + ts_test_fail(TS_CTX, "decoding contents mismatch\n"); break; } } - if (!fine) { - fprintf(stderr, " ERROR: decoding mismatch\n"); - (*fail)++; - } - else - (*ok)++; return; } -static void test_base64(int *ok, int *fail) +TS_TEST(test_base64) { unsigned char ucp[256]; int i; - fprintf(stderr, "\n** Testing str_base64 **\n\n"); - - fprintf(stderr, "1. Encode/Decode of 0 bytes\n"); + ts_test_check(TS_CTX, "encode/decode of 0 bytes"); for (i = 0; i < 256; i++) ucp[i] = 0x55; - test_base64_do(ucp, 256, STR_BASE64_STRICT, ok, fail); + test_base64_do(_t, ucp, 256, STR_BASE64_STRICT); - fprintf(stderr, "2. Encode/Decode of increasing bytes\n"); + ts_test_check(TS_CTX, "encode/decode of increasing bytes\n"); for (i = 0; i < 256; i++) ucp[i] = i; - test_base64_do(ucp, 256, STR_BASE64_STRICT, ok, fail); + test_base64_do(_t, ucp, 256, STR_BASE64_STRICT); - fprintf(stderr, "3. Encode/Decode of distributed bytes\n"); + ts_test_check(TS_CTX, "encode/decode of distributed bytes\n"); for (i = 0; i < 256; i++) ucp[i] = i*31; - test_base64_do(ucp, 256, STR_BASE64_STRICT, ok, fail); + test_base64_do(_t, ucp, 256, STR_BASE64_STRICT); return; } /* - * Main Test Driver Program + * Main Test Suite Procedure */ -struct { - char *name; - void (*func)(int *, int *); - int ok; - int fail; -} tests[] = { - { "Length", test_length, 0, 0 }, - { "Locating", test_locate, 0, 0 }, - { "Spanning", test_span, 0, 0 }, - { "Tokenizing", test_tokenize, 0, 0 }, - { "Parsing", test_parsing, 0, 0 }, - { "Formatting", test_formatting, 0, 0 }, - { "Base64", test_base64, 0, 0 }, - { NULL, NULL, 0,0 } -}; - int main(int argc, char *argv[]) { - int i; - int fail; - int ok; + ts_suite_t *ts; + int n; - ok = 0; - fail = 0; - fprintf(stderr, "\n"); - fprintf(stderr, "String Library Test Suite\n"); - fprintf(stderr, "________________________________________\n\n"); - for (i = 0; tests[i].name != NULL; i++) { - fprintf(stderr, "==== Testing %s ====\n", tests[i].name); - tests[i].ok = tests[i].fail = 0; - tests[i].func(&tests[i].ok, &tests[i].fail); - fprintf(stderr, "==== Tests failed %d/%d ====\n", tests[i].fail, tests[i].ok+tests[i].fail); - fprintf(stderr, "\n"); - ok += tests[i].ok; - fail += tests[i].fail; - } - fprintf(stderr, "________________________________________\n\n"); - fprintf(stderr, "TOTAL: failed %d/%d\n", fail, fail+ok); - fprintf(stderr, "\n"); - return fail; + ts = ts_suite_new("OSSP str (String Handling)"); + ts_suite_test(ts, test_length, "String Length Determination"); + ts_suite_test(ts, test_locate, "String Locating"); + ts_suite_test(ts, test_span, "String Spanning"); + ts_suite_test(ts, test_tokenize, "String Tokenizing"); + ts_suite_test(ts, test_parsing, "String Parsing"); + ts_suite_test(ts, test_formatting, "String Formatting"); + ts_suite_test(ts, test_base64, "String Encoding/Decoding"); + n = ts_suite_run(ts); + ts_suite_free(ts); + return n; } Index: ossp-pkg/str/ts.c RCS File: /v/ossp/cvs/ossp-pkg/str/ts.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/str/ts.c,v' | diff -u /dev/null - -L'ossp-pkg/str/ts.c' 2>/dev/null --- ossp-pkg/str/ts.c +++ - 2025-10-21 05:59:23.951087160 +0200 @@ -0,0 +1,468 @@ +/* +** TS - OSSP Test Suite Library +** Copyright (c) 2001-2002 Ralf S. Engelschall +** Copyright (c) 2001-2002 The OSSP Project +** Copyright (c) 2001-2002 Cable & Wireless Deutschland +** +** This file is part of OSSP TS, a small 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 "config.h" +#if defined(HAVE_DMALLOC_H) && defined(WITH_DMALLOC) +#include "dmalloc.h" +#endif + +#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 ts_test_st { + RING_ENTRY(ts_test_t) next; + char *title; + ts_test_cb_t func; + const char *file; + int line; + RING_HEAD(tstc_t) checks; +}; + +/* test suite */ +struct ts_suite_st { + char *title; + RING_HEAD(ts_test_t) tests; +}; + +/* minimal output-independent vprintf(3) variant which supports %{c,s,d,%} only */ +static int ts_suite_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_suite_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_suite_mvxprintf(NULL, 0, format, ap)) == -1) + return NULL; + if ((buffer = (char *)malloc(n+1)) == NULL) + return NULL; + ts_suite_mvxprintf(buffer, n+1, format, ap2); + return buffer; +} + +/* minimal asprintf(3) variant which supports %{c,s,d} only */ +static char *ts_suite_masprintf(const char *format, ...) +{ + va_list ap; + char *cp; + + va_start(ap, format); + cp = ts_suite_mvasprintf(format, ap); + va_end(ap); + return cp; +} + +/* create test suite */ +ts_suite_t *ts_suite_new(const char *fmt, ...) +{ + ts_suite_t *ts; + va_list ap; + + if ((ts = (ts_suite_t *)malloc(sizeof(ts_suite_t))) == NULL) + return NULL; + va_start(ap, fmt); + ts->title = ts_suite_mvasprintf(fmt, ap); + RING_INIT(&ts->tests, ts_test_t, next); + va_end(ap); + return ts; +} + +/* add test case to test suite */ +void ts_suite_test(ts_suite_t *ts, ts_test_cb_t func, const char *fmt, ...) +{ + ts_test_t *tst; + va_list ap; + + if (ts == NULL || func == NULL || fmt == NULL) + return; + if ((tst = (ts_test_t *)malloc(sizeof(ts_test_t))) == NULL) + return; + RING_ELEM_INIT(tst, next); + va_start(ap, fmt); + tst->title = ts_suite_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, ts_test_t, next); + return; +} + +/* run test suite */ +int ts_suite_run(ts_suite_t *ts) +{ + ts_test_t *tst; + tstc_t *tstc; + tstl_t *tstl; + int total_tests, total_tests_suite_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_suite_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, ts_test_t, next) { + cp = ts_suite_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: %s [%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_suite_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_suite_failed), total_tests_suite_failed, + total_checks, (total_checks - total_checks_failed), total_checks_failed); + if (total_tests_suite_failed > 0) + fprintf(stdout, " Test Suite: FAILED\n"); + else + fprintf(stdout, " Test Suite: OK\n"); + fprintf(stdout, "\n"); + fflush(stdout); + + return total_checks_failed; +} + +/* destroy test suite */ +void ts_suite_free(ts_suite_t *ts) +{ + ts_test_t *tst; + tstc_t *tstc; + tstl_t *tstl; + + if (ts == NULL) + return; + RING_FOREACH(tst, &ts->tests, ts_test_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(ts->title); + free(ts); + return; +} + +/* annotate test case with file name and line number */ +ts_test_t *ts_test_ctx(ts_test_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 ts_test_check(ts_test_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_suite_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 ts_test_fail(ts_test_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_suite_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 ts_test_log(ts_test_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_suite_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/str/ts.h RCS File: /v/ossp/cvs/ossp-pkg/str/ts.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/str/ts.h,v' | diff -u /dev/null - -L'ossp-pkg/str/ts.h' 2>/dev/null --- ossp-pkg/str/ts.h +++ - 2025-10-21 05:59:23.953804266 +0200 @@ -0,0 +1,64 @@ +/* +** TS - OSSP Test Suite Library +** Copyright (c) 2001-2002 Ralf S. Engelschall +** Copyright (c) 2001-2002 The OSSP Project +** Copyright (c) 2001-2002 Cable & Wireless Deutschland +** +** This file is part of OSSP TS, a small 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_ + +/* test suite object type */ +struct ts_suite_st; +typedef struct ts_suite_st ts_suite_t; + +/* test object type */ +struct ts_test_st; +typedef struct ts_test_st ts_test_t; + +/* test callback function type */ +typedef void (*ts_test_cb_t)(ts_test_t *); + +/* test suite operations */ +ts_suite_t *ts_suite_new (const char *fmt, ...); +void ts_suite_test (ts_suite_t *s, ts_test_cb_t func, const char *fmt, ...); +int ts_suite_run (ts_suite_t *s); +void ts_suite_free (ts_suite_t *s); + +/* test operations */ +ts_test_t *ts_test_ctx (ts_test_t *t, const char *file, int line); +void ts_test_check (ts_test_t *t, const char *fmt, ...); +void ts_test_fail (ts_test_t *t, const char *fmt, ...); +void ts_test_log (ts_test_t *t, const char *fmt, ...); + +/* test suite short-cut macros */ +#define TS_TEST(name) \ + static void name(ts_test_t *_t) +#define TS_CTX \ + ts_test_ctx(_t, __FILE__, __LINE__) + +#endif /* _TS_H_ */ +