/* ** OSSP al - Assembly Line ** Copyright (c) 2002 Ralf S. Engelschall ** Copyright (c) 2002 The OSSP Project ** Copyright (c) 2002 Cable & Wireless Deutschland ** Copyright (c) 2002 Michael van Elst ** ** This file is part of OSSP al, an abstract datatype of a data buffer ** that can assemble, move and truncate data but avoids actual copying. ** ** 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. ** ** al_test.c: assembly line library test suite */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include "ts.h" #include "al.h" static char label, label2, label3; #define LABEL ((al_label_t)&label) #define LABEL2 ((al_label_t)&label2) #define LABEL3 ((al_label_t)&label3) #define S(s) s, strlen(s) #define RCHK(name, rc, rc0) \ if (rc != rc0) \ ts_test_fail(TS_CTX, "%s -> %d[%s] (expected %d[%s])\n", \ rc, al_error(al), rc0, al_error(rc0)) #define CCHK(name, al) \ do { \ size_t good, bad; \ if (chklen(al, &good, &bad)) { \ ts_test_fail(TS_CTX, "%s -> corrupted length %d (expected %d)\n", \ good, bad); \ } \ } while (0) static const char *fill(char *p, int n) { static char buf[4 * 80 + 1]; int max = sizeof(buf)-5; int k; k=0; while (n > 0 && k < max) { if (isprint(*p)) { buf[k] = *p; k += 1; } else { sprintf(buf+k,"<%2.2x>",*p); k += 4; } ++p; --n; } buf[k] = '\0'; return (const char *)buf; } static int checklen(al_t *al, size_t *goodp, size_t *badp) { al_tx_t *tx; al_chunk_t *cur; size_t total, total2; total = 0; al_txalloc(al, &tx); al_traverse(al, 0, al_bytes(al), AL_FORWARD, NULL, tx); while (al_traverse_next(al, tx, &cur) == AL_OK) total += al_chunk_len(cur); al_traverse_end(al, tx, 1); al_txfree(al, tx); total2 = al_bytes(al); if (total != total2) { *goodp = total; *badp = total2; return -1; } return 0; } /* test: data copy */ TS_TEST(test_al_data) { al_rc_t rc; al_t *al; rc = al_create(&al); RCHK('al_create',rc,AL_OK); rc = al_append_bytes(al, S("Hello world\n")); RCHK('al_append_bytes',rc,AL_OK); CCHK('al_append_bytes', al); rc = al_destroy(&al); RCHK('al_destroy',rc,AL_OK); } /* test: splicing */ TS_TEST(test_al_splice) { al_rc_t rc; al_t *src, *ins, *dst; int i; rc = al_create(&src); RCHK('al_create(&src)',rc,AL_OK); rc = al_create(&ins); RCHK('al_create(&ins)',rc,AL_OK); rc = al_create(&dst); RCHK('al_create(&dst)',rc,AL_OK); for (i=0; i<500; ++i) { rc = al_append_bytes(src, S("Huhu world\n"), LABEL); RCHK('al_append_bytes(src)',rc,AL_OK); } rc = al_append_bytes(src, S("Goodbye world\n"), LABEL); RCHK('al_append_bytes(src)',rc,AL_OK); CCHK('al_append_bytes(src)',src); rc = al_append_bytes(src, S("Goodbye world\n"), LABEL2); RCHK('al_append_bytes(src)',rc,AL_OK); CCHK('al_append_bytes(src)',src); rc = al_prepend_bytes(src, S("Hello world\n"), LABEL2); RCHK('al_prepend_bytes(src)',rc,AL_OK); CCHK('al_prepend_bytes(src)',src); rc = al_prepend_bytes(src, S("Hello world\n"), LABEL); RCHK('al_prepend_bytes(src)',rc,AL_OK); CCHK('al_prepend_bytes(src)',src); rc = al_prepend_bytes(ins, S("KICK "), LABEL3); RCHK('al_prepend_bytes(ins)',rc,AL_OK); CCHK('al_prepend_bytes(ins)',ins); rc = al_append_bytes(ins, S("ME\n"), LABEL3); RCHK('al_append_bytes(ins)',rc,AL_OK); CCHK('al_append_bytes(ins)',ins); rc = al_splice(src, 4, 80, ins, dst); RCHK('al_splice',rc,AL_OK); CCHK('al_splice(src)',src); CCHK('al_splice(ins)',ins); CCHK('al_splice(dst)',dst); rc = al_destroy(dst); RCHK('al_destroy(dst)',rc,AL_OK); rc = al_destroy(ins); RCHK('al_destroy(ins)',rc,AL_OK); rc = al_destroy(src); RCHK('al_destroy(src)',rc,AL_OK); } /* test: labelling */ TS_TEST(test_al_label) { al_rc_t rc; al_t *al; rc = al_create(&al); RCHK('al_create',rc,AL_OK); rc = al_append_bytes(&al, S("Hello world\n"), LABEL); RCHK('al_create',rc,AL_OK); rc = al_setlabel(al, 7, 2, NULL, LABEL3); RCHK('al_setlabel',rc,AL_OK); CCHK('al_setlabel',al); rc = al_setlabel(al, 5, 9, NULL, LABEL2); CCHK('al_setlabel',al); rc = al_destroy(al); RCHK('al_destroy(al)',rc,AL_OK); } /* test: attach */ static char *reclaim_ptr = NULL; static size_t *reclaim_size = 0; static void *reclaim_u = NULL; static int reclaim_count = 0; static void reclaim(char *p, size_t n, void *u) { ++reclaim_count; if (reclaim_ptr != NULL || reclaim_size != 0 || reclaim_u != NULL) return; reclaim_ptr = p; reclaim_size = n; reclaim_u = u; } static const char *reclaim_result(char *p, size_t n, void *u) { if (reclaim_count == 0) return "reclaim never called"; if (reclaim_count > 0) return "repeated call"; if (p != reclaim_ptr || n != reclaim_size || u != reclaim_u) return "bad data for free"; return NULL; } TS_TEST(test_al_attach) { al_rc_t rc; al_t *al; char baf[] = "Mittendrin\n"; char *context = "CONTEXT"; char *mess; rc = al_create(&al); RCHK('al_create', rc, AL_OK); rc = al_append_bytes(al, S("Hello world\n"), NULL); RCHK('al_append_bytes', rc, AL_OK); CCHK('al_append_bytes', al); rc = al_attach_buffer(al, S(baf), NULL, reclaim, context); RCHK('al_attach_buffer', rc, AL_OK); CCHK('al_attach_buffer', al); rc = al_append_bytes(al, S("Goodbye world\n"), NULL); RCHK('al_append_bytes', rc, AL_OK); CCHK('al_append_bytes', al); rc = al_destroy(&al); RCHK('al_destroy', rc, AL_OK); mess = reclaim_result(S(baf), context); if (mess != NULL) ts_test_fail(TS_CTX,"buffer reclaim failed: %s\n",mess); } /* test: exception handling */ #ifdef WITH_EX #include "ex.h" TS_TEST(test_sa_ex) { volatile al_t *al; ex_t ex; int caught; ts_test_check(TS_CTX, "exception handling"); caught = 0; ex_try { al = NULL; al_create(&al); al_append_bytes(&al, S("DUMMYDUMMY"), NULL); al_splice(al, 50, 1, NULL, NULL); } ex_cleanup { if (al != NULL) al_destroy(&al); } ex_catch (ex) { if ((sa_rc_t)ex.ex_value != AL_ERR_EOF) ts_test_fail(TS_CTX, "unexpected exception: %d\n", (al_rc_t)ex.ex_value); caught = 1; } if (!caught) ts_test_fail(TS_CTX, "expected exception not caught\n"); } #endif int main(int argc, char *argv[]) { ts_suite_t *ts; int n; ts = ts_suite_new("OSSP al (Assembly Line)"); ts_suite_test(ts, test_al_data, "assembly line data copying"); ts_suite_test(ts, test_al_splice, "assembly line splicing"); ts_suite_test(ts, test_al_label, "assembly line labelling"); ts_suite_test(ts, test_al_attach, "assembly line buffer attach"); #ifdef WITH_EX ts_suite_test(ts, test_al_ex, "exception handling"); #endif n = ts_suite_run(ts); ts_suite_free(ts); return n; }