ossp-pkg/al/al_test.c
1.1
/*
** OSSP al - Assembly Line
** Copyright (c) 2002 Ralf S. Engelschall <rse@engelschall.com>
** Copyright (c) 2002 The OSSP Project <http://www.ossp.org/>
** Copyright (c) 2002 Cable & Wireless Deutschland <http://www.cw.com/de/>
** Copyright (c) 2002 Michael van Elst <mlelstv@dev.de.cw.net>
**
** 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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#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;
}