summaryrefslogtreecommitdiff
path: root/libmisc/tests
diff options
context:
space:
mode:
Diffstat (limited to 'libmisc/tests')
-rw-r--r--libmisc/tests/test.h21
-rw-r--r--libmisc/tests/test_assert.c65
-rw-r--r--libmisc/tests/test_endian.c32
-rw-r--r--libmisc/tests/test_hash.c30
-rw-r--r--libmisc/tests/test_private.c29
-rw-r--r--libmisc/tests/test_rand.c82
-rw-r--r--libmisc/tests/test_vcall.c74
7 files changed, 333 insertions, 0 deletions
diff --git a/libmisc/tests/test.h b/libmisc/tests/test.h
new file mode 100644
index 0000000..ea13d3c
--- /dev/null
+++ b/libmisc/tests/test.h
@@ -0,0 +1,21 @@
+/* libmisc/tests/test.h - Common test utilities
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC_TESTS_TEST_H_
+#define _LIBMISC_TESTS_TEST_H_
+
+#include <stdio.h>
+#include <stdlib.h> /* for exit() */
+
+#define test_assert(expr) do { \
+ if (!(expr)) { \
+ printf("test failure: %s:%d:%s: %s\n", \
+ __FILE__, __LINE__, __func__, #expr); \
+ exit(1); \
+ } \
+ } while (0)
+
+#endif /* _LIBMISC_TESTS_TEST_H_ */
diff --git a/libmisc/tests/test_assert.c b/libmisc/tests/test_assert.c
new file mode 100644
index 0000000..949b4f9
--- /dev/null
+++ b/libmisc/tests/test_assert.c
@@ -0,0 +1,65 @@
+/* libmisc/tests/test_assert.c - Tests for <libmisc/assert.h>
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <stdbool.h>
+
+#include <libmisc/assert.h>
+
+#include "test.h"
+
+/* Intercept failures *********************************************************/
+
+bool global_failed = false;
+bool global_unreachable = false;
+
+void __assert_msg_fail(const char *expr,
+ const char *file, unsigned int line, const char *func,
+ const char *msg) {
+ static bool in_fail = false;
+ if (!in_fail) {
+ in_fail = true;
+ printf("error: %s:%u:%s(): assertion \"%s\" failed%s%s\n",
+ file, line, func,
+ expr,
+ msg ? ": " : "", msg);
+ }
+ global_failed = true;
+}
+
+#define __builtin_unreachable() do { global_unreachable = true; } while (0)
+
+/* Utilities ******************************************************************/
+
+#define test_should_succeed(test) do { \
+ global_failed = false; \
+ test; \
+ test_assert(global_failed == false); \
+ } while (0)
+
+#define test_should_fail(test) do { \
+ global_failed = false; \
+ test; \
+ test_assert(global_failed == true); \
+ } while (0)
+
+/* Actual tests ***************************************************************/
+
+static_assert(sizeof(char) == 1);
+
+int main() {
+ test_should_succeed(assert(true));
+ test_should_fail(assert(false));
+
+ test_should_succeed(assert_msg(true, "foo"));
+ test_should_fail(assert_msg(false, "foo"));
+ test_should_succeed(assert_msg(true, NULL));
+ test_should_fail(assert_msg(false, NULL));
+
+ test_should_fail(assert_notreached(""));
+ test_assert(global_unreachable == true);
+
+ return 0;
+}
diff --git a/libmisc/tests/test_endian.c b/libmisc/tests/test_endian.c
new file mode 100644
index 0000000..d0b547c
--- /dev/null
+++ b/libmisc/tests/test_endian.c
@@ -0,0 +1,32 @@
+/* libmisc/tests/test_endian.c - Tests for <libmisc/endian.h>
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <string.h> /* for memcmp() */
+
+#include <libmisc/endian.h>
+
+#include "test.h"
+
+int main() {
+ uint8_t act[12] = {0};
+ uint16be_encode(&act[0], UINT16_C(0x1234));
+ uint32be_encode(&act[2], UINT32_C(0x56789ABC));
+ uint16le_encode(&act[6], UINT16_C(0x1234));
+ uint32le_encode(&act[8], UINT32_C(0x56789ABC));
+
+ uint8_t exp[12] = { 0x12, 0x34,
+ 0x56, 0x78, 0x9A, 0xBC,
+ 0x34, 0x12,
+ 0xBC, 0x9A, 0x78, 0x56 };
+ test_assert(memcmp(act, exp, 12) == 0);
+
+ test_assert(uint16be_decode(&act[0]) == UINT16_C(0x1234));
+ test_assert(uint32be_decode(&act[2]) == UINT32_C(0x56789ABC));
+ test_assert(uint16le_decode(&act[6]) == UINT16_C(0x1234));
+ test_assert(uint32le_decode(&act[8]) == UINT32_C(0x56789ABC));
+
+ return 0;
+}
diff --git a/libmisc/tests/test_hash.c b/libmisc/tests/test_hash.c
new file mode 100644
index 0000000..c1af385
--- /dev/null
+++ b/libmisc/tests/test_hash.c
@@ -0,0 +1,30 @@
+/* libmisc/tests/test_hash.c - Tests for <libmisc/hash.h>
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libmisc/hash.h>
+
+#include "test.h"
+
+int main() {
+ test_assert(hash("hello", sizeof("hello")) == hash("hello", sizeof("hello")));
+ test_assert(hash("hello", sizeof("hello")) != hash("Hello", sizeof("Hello")));
+ int one = 1;
+ int two = 2;
+ test_assert(hash(&one, sizeof(int)) != hash("hello", sizeof("hello")));
+ test_assert(hash(&one, sizeof(int)) == hash(&one, sizeof(int)));
+ test_assert(hash(&one, sizeof(int)) != hash(&two, sizeof(int)));
+
+ hash_t myhash;
+ hash_init(&myhash);
+ hash_write(&myhash, "hello", 5);
+ test_assert(myhash == hash("hello", 5));
+ hash_t myhash_a = myhash;
+ hash_write(&myhash, "world", 5);
+ test_assert(myhash != myhash_a);
+ test_assert(myhash == hash("helloworld", 10));
+
+ return 0;
+}
diff --git a/libmisc/tests/test_private.c b/libmisc/tests/test_private.c
new file mode 100644
index 0000000..7aaf1ee
--- /dev/null
+++ b/libmisc/tests/test_private.c
@@ -0,0 +1,29 @@
+/* libmisc/tests/test_private.c - Tests for <libmisc/private.h>
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libmisc/private.h>
+
+struct a {
+ int foo;
+ BEGIN_PRIVATE(A)
+ int bar;
+ END_PRIVATE(A)
+};
+
+#define IMPLEMENTATION_FOR_B YES
+
+struct b {
+ int foo;
+ BEGIN_PRIVATE(B)
+ int bar;
+ END_PRIVATE(B)
+};
+
+int main() {
+ struct b obj;
+ obj.bar = 0;
+ return obj.bar;
+}
diff --git a/libmisc/tests/test_rand.c b/libmisc/tests/test_rand.c
new file mode 100644
index 0000000..fff1b27
--- /dev/null
+++ b/libmisc/tests/test_rand.c
@@ -0,0 +1,82 @@
+/* libmisc/tests/test_rand.c - Tests for <libmisc/rand.h>
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <stdbool.h>
+#include <setjmp.h>
+
+#include <libmisc/rand.h>
+
+#include "test.h"
+
+/* Intercept failures *********************************************************/
+
+jmp_buf *__catch;
+
+void __assert_msg_fail(const char *expr,
+ const char *file, unsigned int line, const char *func,
+ const char *msg) {
+ static bool in_fail = false;
+ if (__catch)
+ longjmp(*__catch, 1);
+ if (!in_fail) {
+ in_fail = true;
+ printf("error: %s:%u:%s(): assertion \"%s\" failed%s%s\n",
+ file, line, func,
+ expr,
+ msg ? ": " : "", msg);
+ }
+ abort();
+}
+
+#define should_abort(cmd) do { \
+ jmp_buf *old_catch = __catch; \
+ jmp_buf env; \
+ __catch = &env; \
+ if (!setjmp(env)) { \
+ cmd; \
+ __catch = old_catch; \
+ test_assert(false); \
+ } else { \
+ __catch = old_catch; \
+ } \
+ } while (0);
+
+/* Actual tests ***************************************************************/
+
+#define ROUNDS 4096
+#define MAX_SEE_ALL 128
+
+static void test_n(uint64_t cnt) {
+ if (cnt == 0 || cnt > UINT64_C(1)<<63) {
+ should_abort(rand_uint63n(cnt));
+ } else {
+ double sum = 0;
+ bool seen[MAX_SEE_ALL] = {0};
+ for (int i = 0; i < ROUNDS; i++) {
+ uint64_t val = rand_uint63n(cnt);
+ sum += ((double)val)/(cnt-1);
+ test_assert(val < cnt);
+ if (cnt < MAX_SEE_ALL)
+ seen[val] = true;
+ }
+ if (cnt > 1) {
+ test_assert(sum/ROUNDS > 0.45);
+ test_assert(sum/ROUNDS < 0.55);
+ }
+ if (cnt < MAX_SEE_ALL) {
+ for (uint64_t i = 0; i < cnt; i++)
+ test_assert(seen[i]);
+ }
+ }
+}
+
+int main() {
+ for (uint8_t i = 0; i < 64; i++)
+ test_n(UINT64_C(1)<<i);
+ for (uint64_t j = 0; j < MAX_SEE_ALL; j++)
+ test_n(j);
+ return 0;
+}
diff --git a/libmisc/tests/test_vcall.c b/libmisc/tests/test_vcall.c
new file mode 100644
index 0000000..f36fc4b
--- /dev/null
+++ b/libmisc/tests/test_vcall.c
@@ -0,0 +1,74 @@
+/* libmisc/tests/test_vcall.c - Tests for <libmisc/vcall.h>
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libmisc/assert.h>
+#include <libmisc/vcall.h>
+
+#include "test.h"
+
+/******************************************************************************/
+
+struct frobber_vtable;
+
+typedef struct {
+ struct frobber_vtable *vtable;
+} implements_frobber;
+
+struct frobber_vtable {
+ int (*frob)(implements_frobber *);
+ int (*frob1)(implements_frobber *, int);
+ void (*frob0)(implements_frobber *);
+};
+
+/******************************************************************************/
+
+struct myclass {
+ int a;
+ implements_frobber;
+};
+static_assert(offsetof(struct myclass, implements_frobber) != 0);
+
+static int myclass_frob(implements_frobber *_self) {
+ struct myclass *self = VCALL_SELF(struct myclass, implements_frobber, _self);
+ test_assert(self);
+ test_assert((void*)self != (void*)_self);
+ return self->a;
+}
+
+static int myclass_frob1(implements_frobber *_self, int arg) {
+ struct myclass *self = VCALL_SELF(struct myclass, implements_frobber, _self);
+ test_assert(self);
+ test_assert((void*)self != (void*)_self);
+ return arg;
+}
+
+static void myclass_frob0(implements_frobber *_self) {
+ struct myclass *self = VCALL_SELF(struct myclass, implements_frobber, _self);
+ test_assert(self);
+ test_assert((void*)self != (void*)_self);
+}
+
+struct frobber_vtable myclass_vtable = {
+ .frob = myclass_frob,
+ .frob1 = myclass_frob1,
+ .frob0 = myclass_frob0,
+};
+
+/******************************************************************************/
+
+#define MAGIC1 909837
+#define MAGIC2 657441
+
+int main() {
+ struct myclass obj = {
+ .implements_frobber = { .vtable = &myclass_vtable },
+ .a = MAGIC1,
+ };
+ test_assert(VCALL(&obj, frob) == MAGIC1);
+ test_assert(VCALL(&obj, frob1, MAGIC2) == MAGIC2);
+ VCALL(&obj, frob0);
+ return 0;
+}