summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am24
-rw-r--r--tests/README8
-rw-r--r--tests/base64.c18
-rw-r--r--tests/send_to_self.c192
-rw-r--r--tests/xml_parse_and_print.c29
-rw-r--r--tests/xml_print_and_parse.c64
6 files changed, 335 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..93c0b82
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,24 @@
+AM_CFLAGS = -Werror -Wall -Wextra -pedantic -std=gnu99
+
+COMMON_FLAGS = $(AM_CFLAGS) $(LIBXML_CFLAGS) $(EXPAT_CFLAGS) \
+ $(GNUTLS_CFLAGS) $(LIBDANE_CFLAGS) $(OPENSSL_CFLAGS) \
+ $(GSASL_CFLAGS) $(UNBOUND_CFLAGS) $(CARES_CFLAGS) $(GPGME_CFLAGS) \
+ $(ICU_I18N_CFLAGS) $(LIBGCRYPT_CFLAGS) $(CURL_CFLAGS) \
+ $(NICE_CFLAGS) $(GLIB_CFLAGS) $(SRTP_CFLAGS) \
+ $(PORTAUDIO_CFLAGS) $(OPUS_CFLAGS) $(NETTLE_CFLAGS)
+COMMON_LDADD = -L$(top_builddir)/src -lrexmpp
+
+send_to_self_CFLAGS = $(COMMON_FLAGS)
+xml_parse_and_print_CFLAGS = $(COMMON_FLAGS)
+xml_print_and_parse_CFLAGS = $(COMMON_FLAGS)
+base64_CFLAGS = $(COMMON_FLAGS)
+
+send_to_self_LDADD = $(COMMON_LDADD)
+xml_parse_and_print_LDADD = $(COMMON_LDADD)
+xml_print_and_parse_LDADD = $(COMMON_LDADD)
+base64_LDADD = $(COMMON_LDADD)
+
+check_PROGRAMS = send_to_self \
+ xml_parse_and_print xml_print_and_parse base64
+TESTS = send_to_self \
+ xml_parse_and_print xml_print_and_parse base64
diff --git a/tests/README b/tests/README
new file mode 100644
index 0000000..7e30213
--- /dev/null
+++ b/tests/README
@@ -0,0 +1,8 @@
+rexmpp tests
+
+These tests make use of an external XMPP server. Environment variables
+used by the tests:
+
+- JID and PASS: credentials.
+
+- TLS_POLICY: "require", "prefer", or "avoid".
diff --git a/tests/base64.c b/tests/base64.c
new file mode 100644
index 0000000..b69ba0e
--- /dev/null
+++ b/tests/base64.c
@@ -0,0 +1,18 @@
+#include <string.h>
+#include "rexmpp_base64.h"
+
+int main () {
+ char *original_plain = "test string";
+ char *original_base64 = "dGVzdCBzdHJpbmc=";
+ char *encoded, *decoded;
+ size_t encoded_len, decoded_len;
+ if (rexmpp_base64_to(original_plain, strlen(original_plain),
+ &encoded, &encoded_len)) {
+ return -1;
+ }
+ if (rexmpp_base64_from(original_base64, strlen(original_base64),
+ &decoded, &decoded_len)) {
+ return -1;
+ }
+ return strcmp(original_plain, decoded) || strcmp(original_base64, encoded);
+}
diff --git a/tests/send_to_self.c b/tests/send_to_self.c
new file mode 100644
index 0000000..2fcb80f
--- /dev/null
+++ b/tests/send_to_self.c
@@ -0,0 +1,192 @@
+/**
+ @file send_to_self.c
+ @brief A basic message sending test
+ @author defanor <defanor@uberspace.net>
+ @date 2022
+ @copyright MIT license.
+
+Connects to a server, sends a message to itself, receives it, checks
+that it's the expected message.
+
+*/
+
+#define TIMEOUT 30
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <syslog.h>
+#include <rexmpp.h>
+#include <rexmpp_sasl.h>
+
+enum test_stage {
+ TEST_CONNECTING,
+ TEST_MESSAGE_SENT,
+ TEST_MESSAGE_RECEIVED,
+ TEST_DONE,
+ TEST_TIMEOUT
+};
+
+enum test_stage stage = TEST_CONNECTING;
+char *jid, *pass, msg_text[256];
+
+void my_logger (rexmpp_t *s, int priority, const char *fmt, va_list args) {
+ (void)s;
+ char *priority_str = "unknown";
+ switch (priority) {
+ case LOG_EMERG: priority_str = "emerg"; break;
+ case LOG_ALERT: priority_str = "alert"; break;
+ case LOG_CRIT: priority_str = "crit"; break;
+ case LOG_ERR: priority_str = "err"; break;
+ case LOG_WARNING: priority_str = "warning"; break;
+ case LOG_NOTICE: priority_str = "notice"; break;
+ case LOG_INFO: priority_str = "info"; break;
+ case LOG_DEBUG: priority_str = "debug"; break;
+ }
+ fprintf(stdout, "[%s] ", priority_str);
+ vfprintf(stdout, fmt, args);
+ fprintf(stdout, "\n");
+}
+
+int my_sasl_property_cb (rexmpp_t *s, rexmpp_sasl_property prop) {
+ if (prop == REXMPP_SASL_PROP_PASSWORD) {
+ rexmpp_sasl_property_set (s, REXMPP_SASL_PROP_PASSWORD, pass);
+ return 0;
+ }
+ if (prop == REXMPP_SASL_PROP_AUTHID) {
+ rexmpp_sasl_property_set (s, REXMPP_SASL_PROP_AUTHID, s->initial_jid.local);
+ return 0;
+ }
+ printf("unhandled SASL property: %d\n", prop);
+ return -1;
+}
+
+int my_xml_in_cb (rexmpp_t *s, rexmpp_xml_t *node) {
+ (void)s;
+ char *xml_buf = rexmpp_xml_serialize(node, 0);
+ printf("recv: %s\n", xml_buf);
+ free(xml_buf);
+ if (stage == TEST_MESSAGE_SENT && rexmpp_xml_match(node, "jabber:client", "message")) {
+ rexmpp_xml_t *body = rexmpp_xml_find_child(node, "jabber:client", "body");
+ if (body != NULL) {
+ char *txt = rexmpp_xml_text_child(body);
+ if (txt != NULL) {
+ if (strcmp(txt, msg_text) == 0) {
+ stage = TEST_MESSAGE_RECEIVED;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int my_xml_out_cb (rexmpp_t *s, rexmpp_xml_t *node) {
+ (void)s;
+ char *xml_buf = rexmpp_xml_serialize(node, 0);
+ printf("send: %s\n", xml_buf);
+ free(xml_buf);
+ return 0;
+}
+
+int main () {
+ jid = getenv("JID");
+ pass = getenv("PASS");
+ char *tls_policy = getenv("TLS_POLICY");
+
+ time_t t = time(NULL);
+ struct tm utc_time;
+ gmtime_r(&t, &utc_time);
+ strftime(msg_text, 256, "The current time is %FT%TZ", &utc_time);
+
+ rexmpp_t s;
+ rexmpp_err_t err;
+ err = rexmpp_init(&s, jid, my_logger);
+ if (err != REXMPP_SUCCESS) {
+ puts("Failed to initialise rexmpp.");
+ return -1;
+ }
+ if (tls_policy != NULL) {
+ if (strcasecmp(tls_policy, "require") == 0) {
+ s.tls_policy = REXMPP_TLS_REQUIRE;
+ } else if (strcasecmp(tls_policy, "prefer") == 0) {
+ s.tls_policy = REXMPP_TLS_PREFER;
+ } else if (strcasecmp(tls_policy, "avoid") == 0) {
+ s.tls_policy = REXMPP_TLS_AVOID;
+ }
+ }
+
+ s.sasl_property_cb = my_sasl_property_cb;
+ s.xml_in_cb = my_xml_in_cb;
+ s.xml_out_cb = my_xml_out_cb;
+
+ fd_set read_fds, write_fds;
+ int nfds;
+ struct timespec tv;
+ struct timespec *mtv;
+ struct timeval tv_ms;
+ struct timeval *mtv_ms;
+ int n = 0;
+
+ do {
+ err = rexmpp_run(&s, &read_fds, &write_fds);
+ if (err == REXMPP_SUCCESS) {
+ puts("done");
+ break;
+ }
+ if (err != REXMPP_E_AGAIN) {
+ printf("error: %s\n", rexmpp_strerror(err));
+ break;
+ }
+
+ if (stage == TEST_CONNECTING && s.stream_state == REXMPP_STREAM_READY) {
+ rexmpp_xml_t *msg =
+ rexmpp_xml_add_id(rexmpp_xml_new_elem("message", "jabber:client"));
+ rexmpp_xml_add_attr(msg, "to", jid);
+ rexmpp_xml_add_attr(msg, "type", "chat");
+ rexmpp_xml_t *body = rexmpp_xml_new_elem("body", NULL);
+ rexmpp_xml_add_text(body, msg_text);
+ rexmpp_xml_add_child(msg, body);
+ rexmpp_send(&s, msg);
+ stage = TEST_MESSAGE_SENT;
+ } else if (stage == TEST_MESSAGE_RECEIVED) {
+ rexmpp_stop(&s);
+ stage = TEST_DONE;
+ }
+
+ time_t now = time(NULL);
+ if (stage != TEST_DONE) {
+ if (stage != TEST_TIMEOUT && difftime(now, t) > TIMEOUT) {
+ puts("Timeout");
+ rexmpp_stop(&s);
+ stage = TEST_TIMEOUT;
+ } else if (stage == TEST_TIMEOUT && difftime(now, t) > TIMEOUT + 10) {
+ puts("Failed to close the stream properly, quitting");
+ rexmpp_done(&s);
+ return -1;
+ }
+ }
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&write_fds);
+ nfds = rexmpp_fds(&s, &read_fds, &write_fds);
+ tv.tv_sec = TIMEOUT;
+ tv.tv_nsec = 0;
+ mtv = rexmpp_timeout(&s, &tv, &tv);
+ mtv_ms = NULL;
+ if (mtv != NULL) {
+ tv_ms.tv_sec = mtv->tv_sec;
+ tv_ms.tv_usec = mtv->tv_nsec / 1000;
+ mtv_ms = &tv_ms;
+ }
+
+ n = select(nfds, &read_fds, &write_fds, NULL, mtv_ms);
+ if (n == -1) {
+ printf("select error: %s\n", strerror(errno));
+ break;
+ }
+ printf("stage = %u\n", stage);
+ } while (1);
+
+ rexmpp_done(&s);
+ return (stage != TEST_DONE);
+}
diff --git a/tests/xml_parse_and_print.c b/tests/xml_parse_and_print.c
new file mode 100644
index 0000000..c76b06f
--- /dev/null
+++ b/tests/xml_parse_and_print.c
@@ -0,0 +1,29 @@
+#include <string.h>
+#include <stdlib.h>
+#include "rexmpp_xml.h"
+
+int main () {
+ int ret = 0;
+
+ char *str = "<foo bar=\"baz\">"
+ "<qux xmlns=\"urn:test\">a b c d</qux>"
+ "<quux e=\"f\" g=\"h\"/>"
+ "</foo>";
+ rexmpp_xml_t *xml = rexmpp_xml_parse (str, strlen(str));
+
+ printf("Input:\n%s\n\n", str);
+ if (xml == NULL) {
+ ret = -1;
+ } else {
+ char *str_new = rexmpp_xml_serialize (xml, 0);
+ if (str_new == NULL) {
+ ret = -2;
+ } else {
+ printf("Output:\n%s\n", str_new);
+ ret = strcmp(str, str_new);
+ free(str_new);
+ }
+ rexmpp_xml_free(xml);
+ }
+ return ret;
+}
diff --git a/tests/xml_print_and_parse.c b/tests/xml_print_and_parse.c
new file mode 100644
index 0000000..9bd7a3f
--- /dev/null
+++ b/tests/xml_print_and_parse.c
@@ -0,0 +1,64 @@
+#include <string.h>
+#include <stdlib.h>
+#include "rexmpp_xml.h"
+
+int main () {
+ int ret = 0;
+
+ rexmpp_xml_attr_t
+ foo_attributes = { .qname = {"bar", NULL},
+ .value = "baz",
+ .next = NULL },
+ quux_attributes_g = { .qname = {"g", NULL},
+ .value = "h",
+ .next = NULL },
+ quux_attributes =
+ { .qname = {"e", NULL},
+ .value = "f",
+ .next = &quux_attributes_g };
+ rexmpp_xml_t
+ quux = { .type = REXMPP_XML_ELEMENT,
+ .alt.elem =
+ { .qname = {"quux", NULL},
+ .attributes = &quux_attributes,
+ .children = NULL
+ },
+ .next = NULL
+ },
+ qux_text = { .type = REXMPP_XML_TEXT,
+ .alt.text = "a b c d",
+ .next = NULL },
+ qux = { .type = REXMPP_XML_ELEMENT,
+ .alt.elem =
+ { .qname = {"qux", "urn:dummy"},
+ .attributes = NULL,
+ .children = &qux_text
+ },
+ .next = &quux
+ },
+ xml =
+ { .type = REXMPP_XML_ELEMENT,
+ .alt.elem =
+ { .qname = {"foo", NULL},
+ .attributes = &foo_attributes,
+ .children = &qux
+ },
+ .next = NULL
+ };
+
+ char *str_new = rexmpp_xml_serialize (&xml, 0);
+ if (str_new == NULL) {
+ ret = -1;
+ } else {
+ rexmpp_xml_t *xml_new = rexmpp_xml_parse (str_new, strlen(str_new));
+ if (xml_new == NULL) {
+ ret = -2;
+ } else {
+ /* Compare the XML structures. */
+ ret = (rexmpp_xml_eq(&xml, xml_new) == 0);
+ rexmpp_xml_free(xml_new);
+ }
+ free(str_new);
+ }
+ return ret;
+}