--- a/Makefile Thu Mar 12 18:48:42 2009 +0200
+++ b/Makefile Thu Mar 12 20:00:48 2009 +0200
@@ -28,7 +28,7 @@
EVSQL_CFLAGS =
EVSQL_LDFLAGS = -levsql -lpq
-BIN_NAMES = nexus
+BIN_NAMES = nexus test
BIN_PATHS = $(addprefix bin/,$(BIN_NAMES))
# modules
@@ -36,6 +36,7 @@
CORE_OBJS = obj/error.o obj/log.o obj/chain.o
SOCK_OBJS = obj/sock.o obj/sock_tcp.o
+SOCK_TEST_OBJS = obj/sock_test.o
SOCK_GNUTLS_OBJS = obj/sock_gnutls.o
LINEPROTO_OBJS = obj/line_proto.o
IRC_OBJS = obj/irc_line.o obj/irc_conn.o obj/irc_net.o obj/irc_chan.o obj/irc_cmd.o obj/irc_nm.o
@@ -50,6 +51,8 @@
# binaries
bin/nexus: ${CORE_OBJS} ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS} ${LINEPROTO_OBJS} ${IRC_OBJS} ${IRC_LOG_OBJS}
+bin/test: ${CORE_OBJS} ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS} ${SOCK_TEST_OBJS} ${LINEPROTO_OBJS} ${IRC_OBJS}
+
# computed
CFLAGS = ${MODE_CFLAGS} ${FIXED_CFLAGS} ${LIBEVENT_CFLAGS} ${GNUTLS_CFLAGS} ${EVSQL_CFLAGS}
LDFLAGS = ${LIBEVENT_LDFLAGS} ${GNUTLS_LDFLAGS} ${EVSQL_LDFLAGS}
--- a/src/sock.h Thu Mar 12 18:48:42 2009 +0200
+++ b/src/sock.h Thu Mar 12 20:00:48 2009 +0200
@@ -80,7 +80,7 @@
*/
err_t sock_tcp_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err);
-/*
+/**
* A simple blocking SSL connect to the given host/service. The connected/handshake'd SSL socket is returned via
* *sock_ptr. In case of errors, additional error information is stored in *err.
*
--- a/src/sock_tcp.c Thu Mar 12 18:48:42 2009 +0200
+++ b/src/sock_tcp.c Thu Mar 12 20:00:48 2009 +0200
@@ -120,7 +120,7 @@
/*
* Our sock_stream_type
*/
-struct sock_stream_type sock_tcp_type = {
+static struct sock_stream_type sock_tcp_type = {
.methods = {
.read = &sock_tcp_read,
.write = &sock_tcp_write,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sock_test.c Thu Mar 12 20:00:48 2009 +0200
@@ -0,0 +1,170 @@
+#include "sock_test.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+static err_t sock_test_read (struct sock_stream *base_sock, void *buf_ptr, size_t *len)
+{
+ struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test);
+ struct io_buf *buf = &sock->recv_buf;
+ struct io_vec *vec = buf->vec;
+
+ // no current vector -> EOF
+ if (!vec)
+ return ERR_READ_EOF;
+
+ // vector past the end -> EOF
+ if (vec == &buf->vecs[buf->count])
+ return ERR_READ_EOF;
+
+ // no data left in current vector -> EOF
+ if (buf->off >= vec->len)
+ return ERR_READ_EOF;
+
+ // amount of data available in this iovec
+ size_t available = vec->len - buf->off;
+
+ // amount to read
+ size_t to_read = *len;
+
+ // trim down?
+ if (to_read > available)
+ to_read = available;
+
+ // copy
+ memcpy(buf_ptr, vec->buf + buf->off, to_read);
+
+ // consumed the whole vec?
+ if (to_read < available) {
+ // move offset
+ buf->off += to_read;
+
+ } else {
+ // next vector
+ buf->vec++;
+ }
+
+ // update len
+ *len = to_read;
+
+ // ok
+ return SUCCESS;
+}
+
+static err_t sock_test_write (struct sock_stream *base_sock, const void *buf_ptr, size_t *len)
+{
+ struct sock_test *sock = SOCK_FROM_BASE(base_sock, struct sock_test);
+ struct io_buf *buf = &sock->send_buf;
+ struct io_vec *vec = buf->vec;
+
+ // vectors full?
+ if (buf->vecs == NULL || vec == &buf->vecs[buf->count]) {
+ size_t vec_offset = vec ? (vec - buf->vecs) : 0;
+ struct io_vec *v;
+
+ // new size
+ buf->count = buf->count * 2 + 1;
+
+ // grow
+ assert((buf->vecs = realloc(buf->vecs, buf->count * sizeof(struct io_vec))));
+
+ // set vec
+ vec = buf->vec = buf->vecs + vec_offset;
+
+ // zero
+ for (v = vec; v < &buf->vecs[buf->count]; v++) {
+ v->buf = NULL;
+ v->len = 0;
+ }
+ }
+
+ // store
+ vec->len = *len;
+ assert((vec->buf = malloc(vec->len)));
+ memcpy(vec->buf, buf_ptr, vec->len);
+
+ // move vec onwards
+ buf->vec++;
+
+ // ok
+ return SUCCESS;
+}
+
+static err_t sock_test_event_init (struct sock_stream *base_sock)
+{
+
+ return SUCCESS;
+}
+
+static err_t sock_test_event_enable (struct sock_stream *base_sock, short mask)
+{
+
+ return SUCCESS;
+}
+
+static void sock_test_release (struct sock_stream *base_sock)
+{
+
+}
+
+/*
+ * Our sock_stream_type
+ */
+static struct sock_stream_type sock_test_type = {
+ .methods = {
+ .read = &sock_test_read,
+ .write = &sock_test_write,
+ .event_init = &sock_test_event_init,
+ .event_enable = &sock_test_event_enable,
+ .release = &sock_test_release,
+ },
+};
+
+struct sock_test* sock_test_create (void)
+{
+ struct sock_test *sock;
+
+ // allocate
+ assert((sock = calloc(1, sizeof(*sock))));
+
+ // initialize base with our sock_stream_type
+ sock_stream_init(SOCK_TEST_BASE(sock), &sock_test_type);
+
+ // ok
+ return sock;
+}
+
+void sock_test_set_recv_buffer (struct sock_test *sock, struct io_vec *vecs, size_t count)
+{
+ sock->recv_buf.vecs = vecs;
+ sock->recv_buf.count = count;
+ sock->recv_buf.vec = vecs;
+ sock->recv_buf.off = 0;
+}
+
+void sock_test_get_send_data (struct sock_test *sock, char **buf_ptr, size_t *len_ptr)
+{
+ struct io_buf *buf = &sock->send_buf;
+ size_t len = 0, i, off = 0;
+ char *out;
+
+ // calculate total size
+ for (i = 0; i < buf->count; i++) {
+ len += buf->vecs[i].len;
+ }
+
+ // alloc
+ assert((out = malloc(len)));
+
+ // copy
+ for (i = 0; i < buf->count; i++) {
+ memcpy(out + off, buf->vecs[i].buf, buf->vecs[i].len);
+ off += buf->vecs[i].len;
+ }
+
+ // update return
+ *buf_ptr = out;
+ *len_ptr = len;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sock_test.h Thu Mar 12 20:00:48 2009 +0200
@@ -0,0 +1,72 @@
+#ifndef SOCK_TEST_H
+#define SOCK_TEST_H
+
+/**
+ * @file
+ *
+ * Dummy sock_stream implemention for local testing.
+ */
+#include "sock_internal.h"
+
+/**
+ * IO vector
+ */
+struct io_vec {
+ /** The buffer */
+ char *buf;
+
+ /** Buffer size */
+ size_t len;
+};
+
+/**
+ * Vectored IO-buffer
+ */
+struct io_buf {
+ /** The array of buffer-vectors, {NULL}-terminated */
+ struct io_vec *vecs;
+
+ /** The number of io_vecs */
+ size_t count;
+
+ /** Current vector */
+ struct io_vec *vec;
+
+ /** Offset into current vector */
+ size_t off;
+};
+
+/**
+ * The per-socket state
+ */
+struct sock_test {
+ /** The base struct for sock_stream_* functions */
+ struct sock_stream base;
+
+ /** The send/recieve buffers */
+ struct io_buf send_buf, recv_buf;
+};
+
+/**
+ * Get a sock_stream pointer from a sock_tcp pointer
+ */
+#define SOCK_TEST_BASE(sock_ptr) (&(sock_ptr)->base)
+
+/**
+ * A dummy stream socket intended for testing purposes.
+ */
+struct sock_test* sock_test_create (void);
+
+/**
+ * Set the recieve buffer contents.
+ *
+ * The data is not copied, but the vectors are stored as-is.
+ */
+void sock_test_set_recv_buffer (struct sock_test *sock, struct io_vec *vecs, size_t count);
+
+/**
+ * Get the send buffer contents as a single string, free() after use if you care about that
+ */
+void sock_test_get_send_data (struct sock_test *sock, char **buf, size_t *len);
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test.c Thu Mar 12 20:00:48 2009 +0200
@@ -0,0 +1,118 @@
+/**
+ * The main test code entry point
+ */
+#include "sock_test.h"
+#include "irc_conn.h"
+#include "log.h"
+
+#include <string.h>
+#include <assert.h>
+
+void assert_sock_read (struct sock_stream *sock, const char *str)
+{
+ char buf[strlen(str)];
+
+ log_debug("read: %p: '%s'", sock, str);
+
+ // read it
+ assert(sock_stream_read(sock, buf, strlen(str)) == (int) strlen(str));
+
+ // cmp
+ assert(strncmp(buf, str, strlen(str)) == 0);
+}
+
+void assert_sock_write (struct sock_stream *sock, const char *str)
+{
+ log_debug("write: %p: '%s'", sock, str);
+
+ // write it
+ assert(sock_stream_write(sock, str, strlen(str)) == (int) strlen(str));
+}
+
+void test_sock_test (void)
+{
+ struct sock_test *sock = sock_test_create();
+ struct io_vec _read_data[] = {
+ { "foo", 3 },
+ { "barx", 4 }
+ };
+ const char *_write_data = "test data";
+
+ // put the read data
+ log_debug("set_recv_buffer: %p, %d", _read_data, 2);
+ sock_test_set_recv_buffer(sock, _read_data, 2);
+
+ // read it out
+ assert_sock_read(SOCK_TEST_BASE(sock), "foo");
+ assert_sock_read(SOCK_TEST_BASE(sock), "ba");
+ assert_sock_read(SOCK_TEST_BASE(sock), "rx");
+
+ // write the data in
+ assert_sock_write(SOCK_TEST_BASE(sock), "test ");
+ assert_sock_write(SOCK_TEST_BASE(sock), "data");
+
+ // get the data out
+ char *data;
+ size_t len;
+
+ sock_test_get_send_data(sock, &data, &len);
+
+ log_debug("get_send_data: %u: '%s'", len, data);
+
+ // should be the same
+ assert(len == strlen(_write_data));
+ assert(strncmp(data, _write_data, len) == 0);
+}
+
+static struct irc_conn_callbacks _conn_callbacks = {
+ .on_registered = NULL,
+};
+
+void test_irc_conn (void)
+{
+ struct sock_test *sock;
+ struct irc_conn *conn;
+ struct error_info err;
+
+ // create the test socket
+ assert((sock = sock_test_create()));
+
+ // create the irc_conn
+ assert(irc_conn_create(&conn, SOCK_TEST_BASE(sock), &_conn_callbacks, NULL, &err) == SUCCESS);
+
+ // destroy it
+ irc_conn_destroy(conn);
+}
+
+/**
+ * Test definition
+ */
+static struct test {
+ /** Test name */
+ const char *name;
+
+ /** Test func */
+ void (*func) (void);
+
+} _tests[] = {
+ { "sock_test", &test_sock_test },
+ { "irc_conn", &test_irc_conn },
+ { NULL, NULL }
+};
+
+int main (int argc, char **argv)
+{
+ struct test *test;
+
+ (void) argv;
+
+ // no arguments
+ assert(argc == 1);
+
+ // run tests
+ for (test = _tests; test->name; test++) {
+ log_info("Running test: %s", test->name);
+
+ test->func();
+ }
+}