From 3206124fb3af2481fc45e705f7bba3ea56016433 Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@tavianator.com>
Date: Sun, 7 Jul 2024 12:59:39 -0400
Subject: tests: Simplify unit tests with a global variable

It's a little awkward to thread the test result through manually; much
easier to just make bfs_check() update a global variable.
---
 tests/alloc.c   |  23 +++++------
 tests/bfstd.c   | 101 +++++++++++++++++++++++-------------------------
 tests/bit.c     | 112 ++++++++++++++++++++++++++----------------------------
 tests/ioq.c     |   3 +-
 tests/list.c    |   4 +-
 tests/main.c    |  19 +++++++++-
 tests/sighook.c |  31 +++++----------
 tests/tests.h   |  32 +++++++---------
 tests/trie.c    |  47 +++++++++++------------
 tests/xspawn.c  |  99 +++++++++++++++++++----------------------------
 tests/xtime.c   | 116 ++++++++++++++++++++++++--------------------------------
 11 files changed, 263 insertions(+), 324 deletions(-)

diff --git a/tests/alloc.c b/tests/alloc.c
index 6c0defd..2d3077d 100644
--- a/tests/alloc.c
+++ b/tests/alloc.c
@@ -9,33 +9,31 @@
 #include <stdlib.h>
 #include <stdint.h>
 
-bool check_alloc(void) {
-	bool ret = true;
-
+void check_alloc(void) {
 	// Check sizeof_flex()
 	struct flexible {
 		alignas(64) int foo[8];
 		int bar[];
 	};
-	ret &= bfs_check(sizeof_flex(struct flexible, bar, 0) >= sizeof(struct flexible));
-	ret &= bfs_check(sizeof_flex(struct flexible, bar, 16) % alignof(struct flexible) == 0);
+	bfs_check(sizeof_flex(struct flexible, bar, 0) >= sizeof(struct flexible));
+	bfs_check(sizeof_flex(struct flexible, bar, 16) % alignof(struct flexible) == 0);
 
 	size_t too_many = SIZE_MAX / sizeof(int) + 1;
-	ret &= bfs_check(sizeof_flex(struct flexible, bar, too_many) == align_floor(alignof(struct flexible), SIZE_MAX));
+	bfs_check(sizeof_flex(struct flexible, bar, too_many) == align_floor(alignof(struct flexible), SIZE_MAX));
 
 	// Corner case: sizeof(type) > align_ceil(alignof(type), offsetof(type, member))
 	// Doesn't happen in typical ABIs
-	ret &= bfs_check(flex_size(8, 16, 4, 4, 1) == 16);
+	bfs_check(flex_size(8, 16, 4, 4, 1) == 16);
 
 	// Make sure we detect allocation size overflows
 #if __GNUC__ && !__clang__
 #  pragma GCC diagnostic ignored "-Walloc-size-larger-than="
 #endif
 
-	ret &= bfs_check(ALLOC_ARRAY(int, too_many) == NULL && errno == EOVERFLOW);
-	ret &= bfs_check(ZALLOC_ARRAY(int, too_many) == NULL && errno == EOVERFLOW);
-	ret &= bfs_check(ALLOC_FLEX(struct flexible, bar, too_many) == NULL && errno == EOVERFLOW);
-	ret &= bfs_check(ZALLOC_FLEX(struct flexible, bar, too_many) == NULL && errno == EOVERFLOW);
+	bfs_check(ALLOC_ARRAY(int, too_many) == NULL && errno == EOVERFLOW);
+	bfs_check(ZALLOC_ARRAY(int, too_many) == NULL && errno == EOVERFLOW);
+	bfs_check(ALLOC_FLEX(struct flexible, bar, too_many) == NULL && errno == EOVERFLOW);
+	bfs_check(ZALLOC_FLEX(struct flexible, bar, too_many) == NULL && errno == EOVERFLOW);
 
 	// varena tests
 	struct varena varena;
@@ -44,9 +42,8 @@ bool check_alloc(void) {
 	for (size_t i = 0; i < 256; ++i) {
 		bfs_verify(varena_alloc(&varena, i));
 		struct arena *arena = &varena.arenas[varena.narenas - 1];
-		ret &= bfs_check(arena->size >= sizeof_flex(struct flexible, bar, i));
+		bfs_check(arena->size >= sizeof_flex(struct flexible, bar, i));
 	}
 
 	varena_destroy(&varena);
-	return ret;
 }
diff --git a/tests/bfstd.c b/tests/bfstd.c
index f0f61ce..e59ac34 100644
--- a/tests/bfstd.c
+++ b/tests/bfstd.c
@@ -11,83 +11,76 @@
 #include <string.h>
 
 /** Check the result of xdirname()/xbasename(). */
-static bool check_base_dir(const char *path, const char *dir, const char *base) {
-	bool ret = true;
-
+static void check_base_dir(const char *path, const char *dir, const char *base) {
 	char *xdir = xdirname(path);
 	bfs_everify(xdir, "xdirname()");
-	ret &= bfs_check(strcmp(xdir, dir) == 0, "xdirname('%s') == '%s' (!= '%s')", path, xdir, dir);
+	bfs_check(strcmp(xdir, dir) == 0, "xdirname('%s') == '%s' (!= '%s')", path, xdir, dir);
 	free(xdir);
 
 	char *xbase = xbasename(path);
 	bfs_everify(xbase, "xbasename()");
-	ret &= bfs_check(strcmp(xbase, base) == 0, "xbasename('%s') == '%s' (!= '%s')", path, xbase, base);
+	bfs_check(strcmp(xbase, base) == 0, "xbasename('%s') == '%s' (!= '%s')", path, xbase, base);
 	free(xbase);
-
-	return ret;
 }
 
 /** Check the result of wordesc(). */
-static bool check_wordesc(const char *str, const char *exp, enum wesc_flags flags) {
+static void check_wordesc(const char *str, const char *exp, enum wesc_flags flags) {
 	char buf[256];
 	char *end = buf + sizeof(buf);
 	char *esc = wordesc(buf, end, str, flags);
 
-	return bfs_check(esc != end)
-		&& bfs_check(strcmp(buf, exp) == 0, "wordesc('%s') == '%s' (!= '%s')", str, buf, exp);
+	if (bfs_check(esc != end)) {
+		bfs_check(strcmp(buf, exp) == 0, "wordesc('%s') == '%s' (!= '%s')", str, buf, exp);
+	}
 }
 
-bool check_bfstd(void) {
-	bool ret = true;
-
-	ret &= bfs_check(asciilen("") == 0);
-	ret &= bfs_check(asciilen("@") == 1);
-	ret &= bfs_check(asciilen("@@") == 2);
-	ret &= bfs_check(asciilen("\xFF@") == 0);
-	ret &= bfs_check(asciilen("@\xFF") == 1);
-	ret &= bfs_check(asciilen("@@@@@@@@") == 8);
-	ret &= bfs_check(asciilen("@@@@@@@@@@@@@@@@") == 16);
-	ret &= bfs_check(asciilen("@@@@@@@@@@@@@@@@@@@@@@@@") == 24);
-	ret &= bfs_check(asciilen("@@@@@@@@@@@@@@a\xFF@@@@@@@") == 15);
-	ret &= bfs_check(asciilen("@@@@@@@@@@@@@@@@\xFF@@@@@@@") == 16);
-	ret &= bfs_check(asciilen("@@@@@@@@@@@@@@@@a\xFF@@@@@@") == 17);
-	ret &= bfs_check(asciilen("@@@@@@@\xFF@@@@@@a\xFF@@@@@@@") == 7);
-	ret &= bfs_check(asciilen("@@@@@@@@\xFF@@@@@a\xFF@@@@@@@") == 8);
-	ret &= bfs_check(asciilen("@@@@@@@@@\xFF@@@@a\xFF@@@@@@@") == 9);
+void check_bfstd(void) {
+	bfs_check(asciilen("") == 0);
+	bfs_check(asciilen("@") == 1);
+	bfs_check(asciilen("@@") == 2);
+	bfs_check(asciilen("\xFF@") == 0);
+	bfs_check(asciilen("@\xFF") == 1);
+	bfs_check(asciilen("@@@@@@@@") == 8);
+	bfs_check(asciilen("@@@@@@@@@@@@@@@@") == 16);
+	bfs_check(asciilen("@@@@@@@@@@@@@@@@@@@@@@@@") == 24);
+	bfs_check(asciilen("@@@@@@@@@@@@@@a\xFF@@@@@@@") == 15);
+	bfs_check(asciilen("@@@@@@@@@@@@@@@@\xFF@@@@@@@") == 16);
+	bfs_check(asciilen("@@@@@@@@@@@@@@@@a\xFF@@@@@@") == 17);
+	bfs_check(asciilen("@@@@@@@\xFF@@@@@@a\xFF@@@@@@@") == 7);
+	bfs_check(asciilen("@@@@@@@@\xFF@@@@@a\xFF@@@@@@@") == 8);
+	bfs_check(asciilen("@@@@@@@@@\xFF@@@@a\xFF@@@@@@@") == 9);
 
 	// From man 3p basename
-	ret &= check_base_dir("usr", ".", "usr");
-	ret &= check_base_dir("usr/", ".", "usr");
-	ret &= check_base_dir("", ".", ".");
-	ret &= check_base_dir("/", "/", "/");
+	check_base_dir("usr", ".", "usr");
+	check_base_dir("usr/", ".", "usr");
+	check_base_dir("", ".", ".");
+	check_base_dir("/", "/", "/");
 	// check_base_dir("//", "/" or "//", "/" or "//");
-	ret &= check_base_dir("///", "/", "/");
-	ret &= check_base_dir("/usr/", "/", "usr");
-	ret &= check_base_dir("/usr/lib", "/usr", "lib");
-	ret &= check_base_dir("//usr//lib//", "//usr", "lib");
-	ret &= check_base_dir("/home//dwc//test", "/home//dwc", "test");
+	check_base_dir("///", "/", "/");
+	check_base_dir("/usr/", "/", "usr");
+	check_base_dir("/usr/lib", "/usr", "lib");
+	check_base_dir("//usr//lib//", "//usr", "lib");
+	check_base_dir("/home//dwc//test", "/home//dwc", "test");
 
-	ret &= check_wordesc("", "\"\"", WESC_SHELL);
-	ret &= check_wordesc("word", "word", WESC_SHELL);
-	ret &= check_wordesc("two words", "\"two words\"", WESC_SHELL);
-	ret &= check_wordesc("word's", "\"word's\"", WESC_SHELL);
-	ret &= check_wordesc("\"word\"", "'\"word\"'", WESC_SHELL);
-	ret &= check_wordesc("\"word's\"", "'\"word'\\''s\"'", WESC_SHELL);
-	ret &= check_wordesc("\033[1mbold's\033[0m", "$'\\e[1mbold\\'s\\e[0m'", WESC_SHELL | WESC_TTY);
-	ret &= check_wordesc("\x7F", "$'\\x7F'", WESC_SHELL | WESC_TTY);
-	ret &= check_wordesc("~user", "\"~user\"", WESC_SHELL);
+	check_wordesc("", "\"\"", WESC_SHELL);
+	check_wordesc("word", "word", WESC_SHELL);
+	check_wordesc("two words", "\"two words\"", WESC_SHELL);
+	check_wordesc("word's", "\"word's\"", WESC_SHELL);
+	check_wordesc("\"word\"", "'\"word\"'", WESC_SHELL);
+	check_wordesc("\"word's\"", "'\"word'\\''s\"'", WESC_SHELL);
+	check_wordesc("\033[1mbold's\033[0m", "$'\\e[1mbold\\'s\\e[0m'", WESC_SHELL | WESC_TTY);
+	check_wordesc("\x7F", "$'\\x7F'", WESC_SHELL | WESC_TTY);
+	check_wordesc("~user", "\"~user\"", WESC_SHELL);
 
 	const char *charmap = nl_langinfo(CODESET);
 	if (strcmp(charmap, "UTF-8") == 0) {
-		ret &= check_wordesc("\xF0", "$'\\xF0'", WESC_SHELL | WESC_TTY);
-		ret &= check_wordesc("\xF0\x9F", "$'\\xF0\\x9F'", WESC_SHELL | WESC_TTY);
-		ret &= check_wordesc("\xF0\x9F\x98", "$'\\xF0\\x9F\\x98'", WESC_SHELL | WESC_TTY);
-		ret &= check_wordesc("\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80", WESC_SHELL | WESC_TTY);
-		ret &= check_wordesc("\xCB\x9Cuser", "\xCB\x9Cuser", WESC_SHELL);
+		check_wordesc("\xF0", "$'\\xF0'", WESC_SHELL | WESC_TTY);
+		check_wordesc("\xF0\x9F", "$'\\xF0\\x9F'", WESC_SHELL | WESC_TTY);
+		check_wordesc("\xF0\x9F\x98", "$'\\xF0\\x9F\\x98'", WESC_SHELL | WESC_TTY);
+		check_wordesc("\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80", WESC_SHELL | WESC_TTY);
+		check_wordesc("\xCB\x9Cuser", "\xCB\x9Cuser", WESC_SHELL);
 	}
 
-	ret &= bfs_check(xstrwidth("Hello world") == 11);
-	ret &= bfs_check(xstrwidth("Hello\1world") == 10);
-
-	return ret;
+	bfs_check(xstrwidth("Hello world") == 11);
+	bfs_check(xstrwidth("Hello\1world") == 10);
 }
diff --git a/tests/bit.c b/tests/bit.c
index 49e167d..64fb5ea 100644
--- a/tests/bit.c
+++ b/tests/bit.c
@@ -56,86 +56,82 @@ bfs_static_assert(INTMAX_MAX == IWIDTH_MAX(INTMAX_WIDTH));
 #define check_eq(a, b) \
 	bfs_check((a) == (b), "(0x%jX) %s != %s (0x%jX)", (uintmax_t)(a), #a, #b, (uintmax_t)(b))
 
-bool check_bit(void) {
-	bool ret = true;
-
+void check_bit(void) {
 	const char *str = "\x1\x2\x3\x4";
 	uint32_t word;
 	memcpy(&word, str, sizeof(word));
 
 #if ENDIAN_NATIVE == ENDIAN_LITTLE
-	ret &= check_eq(word, 0x04030201);
+	check_eq(word, 0x04030201);
 #elif ENDIAN_NATIVE == ENDIAN_BIG
-	ret &= check_eq(word, 0x01020304);
+	check_eq(word, 0x01020304);
 #else
 #  warning "Skipping byte order tests on mixed/unknown-endian machine"
 #endif
 
-	ret &= check_eq(bswap((uint8_t)0x12), 0x12);
-	ret &= check_eq(bswap((uint16_t)0x1234), 0x3412);
-	ret &= check_eq(bswap((uint32_t)0x12345678), 0x78563412);
-	ret &= check_eq(bswap((uint64_t)0x1234567812345678), 0x7856341278563412);
-
-	ret &= check_eq(count_ones(0x0U), 0);
-	ret &= check_eq(count_ones(0x1U), 1);
-	ret &= check_eq(count_ones(0x2U), 1);
-	ret &= check_eq(count_ones(0x3U), 2);
-	ret &= check_eq(count_ones(0x137FU), 10);
-
-	ret &= check_eq(count_zeros(0U), UINT_WIDTH);
-	ret &= check_eq(count_zeros(0UL), ULONG_WIDTH);
-	ret &= check_eq(count_zeros(0ULL), ULLONG_WIDTH);
-	ret &= check_eq(count_zeros((uint8_t)0), 8);
-	ret &= check_eq(count_zeros((uint16_t)0), 16);
-	ret &= check_eq(count_zeros((uint32_t)0), 32);
-	ret &= check_eq(count_zeros((uint64_t)0), 64);
-
-	ret &= check_eq(rotate_left((uint8_t)0xA1, 4), 0x1A);
-	ret &= check_eq(rotate_left((uint16_t)0x1234, 12), 0x4123);
-	ret &= check_eq(rotate_left((uint32_t)0x12345678, 20), 0x67812345);
-	ret &= check_eq(rotate_left((uint32_t)0x12345678, 0), 0x12345678);
-
-	ret &= check_eq(rotate_right((uint8_t)0xA1, 4), 0x1A);
-	ret &= check_eq(rotate_right((uint16_t)0x1234, 12), 0x2341);
-	ret &= check_eq(rotate_right((uint32_t)0x12345678, 20), 0x45678123);
-	ret &= check_eq(rotate_right((uint32_t)0x12345678, 0), 0x12345678);
+	check_eq(bswap((uint8_t)0x12), 0x12);
+	check_eq(bswap((uint16_t)0x1234), 0x3412);
+	check_eq(bswap((uint32_t)0x12345678), 0x78563412);
+	check_eq(bswap((uint64_t)0x1234567812345678), 0x7856341278563412);
+
+	check_eq(count_ones(0x0U), 0);
+	check_eq(count_ones(0x1U), 1);
+	check_eq(count_ones(0x2U), 1);
+	check_eq(count_ones(0x3U), 2);
+	check_eq(count_ones(0x137FU), 10);
+
+	check_eq(count_zeros(0U), UINT_WIDTH);
+	check_eq(count_zeros(0UL), ULONG_WIDTH);
+	check_eq(count_zeros(0ULL), ULLONG_WIDTH);
+	check_eq(count_zeros((uint8_t)0), 8);
+	check_eq(count_zeros((uint16_t)0), 16);
+	check_eq(count_zeros((uint32_t)0), 32);
+	check_eq(count_zeros((uint64_t)0), 64);
+
+	check_eq(rotate_left((uint8_t)0xA1, 4), 0x1A);
+	check_eq(rotate_left((uint16_t)0x1234, 12), 0x4123);
+	check_eq(rotate_left((uint32_t)0x12345678, 20), 0x67812345);
+	check_eq(rotate_left((uint32_t)0x12345678, 0), 0x12345678);
+
+	check_eq(rotate_right((uint8_t)0xA1, 4), 0x1A);
+	check_eq(rotate_right((uint16_t)0x1234, 12), 0x2341);
+	check_eq(rotate_right((uint32_t)0x12345678, 20), 0x45678123);
+	check_eq(rotate_right((uint32_t)0x12345678, 0), 0x12345678);
 
 	for (unsigned int i = 0; i < 16; ++i) {
 		uint16_t n = (uint16_t)1 << i;
 		for (unsigned int j = i; j < 16; ++j) {
 			uint16_t m = (uint16_t)1 << j;
 			uint16_t nm = n | m;
-			ret &= check_eq(count_ones(nm), 1 + (n != m));
-			ret &= check_eq(count_zeros(nm), 15 - (n != m));
-			ret &= check_eq(leading_zeros(nm), 15 - j);
-			ret &= check_eq(trailing_zeros(nm), i);
-			ret &= check_eq(first_leading_one(nm), 16 - j);
-			ret &= check_eq(first_trailing_one(nm), i + 1);
-			ret &= check_eq(bit_width(nm), j + 1);
-			ret &= check_eq(bit_floor(nm), m);
+			check_eq(count_ones(nm), 1 + (n != m));
+			check_eq(count_zeros(nm), 15 - (n != m));
+			check_eq(leading_zeros(nm), 15 - j);
+			check_eq(trailing_zeros(nm), i);
+			check_eq(first_leading_one(nm), 16 - j);
+			check_eq(first_trailing_one(nm), i + 1);
+			check_eq(bit_width(nm), j + 1);
+			check_eq(bit_floor(nm), m);
 			if (n == m) {
-				ret &= check_eq(bit_ceil(nm), m);
-				ret &= bfs_check(has_single_bit(nm));
+				check_eq(bit_ceil(nm), m);
+				bfs_check(has_single_bit(nm));
 			} else {
 				if (j < 15) {
-					ret &= check_eq(bit_ceil(nm), (m << 1));
+					check_eq(bit_ceil(nm), (m << 1));
 				}
-				ret &= bfs_check(!has_single_bit(nm));
+				bfs_check(!has_single_bit(nm));
 			}
 		}
 	}
 
-	ret &= check_eq(leading_zeros((uint16_t)0), 16);
-	ret &= check_eq(trailing_zeros((uint16_t)0), 16);
-	ret &= check_eq(first_leading_one(0U), 0);
-	ret &= check_eq(first_trailing_one(0U), 0);
-	ret &= check_eq(bit_width(0U), 0);
-	ret &= check_eq(bit_floor(0U), 0);
-	ret &= check_eq(bit_ceil(0U), 1);
-
-	ret &= bfs_check(!has_single_bit(0U));
-	ret &= bfs_check(!has_single_bit(UINT32_MAX));
-	ret &= bfs_check(has_single_bit((uint32_t)1 << (UINT_WIDTH - 1)));
-
-	return ret;
+	check_eq(leading_zeros((uint16_t)0), 16);
+	check_eq(trailing_zeros((uint16_t)0), 16);
+	check_eq(first_leading_one(0U), 0);
+	check_eq(first_trailing_one(0U), 0);
+	check_eq(bit_width(0U), 0);
+	check_eq(bit_floor(0U), 0);
+	check_eq(bit_ceil(0U), 1);
+
+	bfs_check(!has_single_bit(0U));
+	bfs_check(!has_single_bit(UINT32_MAX));
+	bfs_check(has_single_bit((uint32_t)1 << (UINT_WIDTH - 1)));
 }
diff --git a/tests/ioq.c b/tests/ioq.c
index 99c98a2..4e1209e 100644
--- a/tests/ioq.c
+++ b/tests/ioq.c
@@ -71,7 +71,6 @@ static void check_ioq_push_block(void) {
 	ioq_destroy(ioq);
 }
 
-bool check_ioq(void) {
+void check_ioq(void) {
 	check_ioq_push_block();
-	return true;
 }
diff --git a/tests/list.c b/tests/list.c
index e14570f..822077e 100644
--- a/tests/list.c
+++ b/tests/list.c
@@ -41,7 +41,7 @@ static bool check_list_items(struct list *list, int *array, size_t size) {
 #define ARRAY(...) (int[]){ __VA_ARGS__ }, countof((int[]){ __VA_ARGS__ })
 #define EMPTY() NULL, 0
 
-bool check_list(void) {
+void check_list(void) {
 	struct list l1;
 	SLIST_INIT(&l1);
 	bfs_verify(check_list_items(&l1, EMPTY()));
@@ -92,6 +92,4 @@ bool check_list(void) {
 	SLIST_APPEND(&l2, &i12);
 	SLIST_SPLICE(&l1, &l1.head->next, &l2);
 	bfs_verify(check_list_items(&l1, ARRAY(10, 11, 12, 15, 20)));
-
-	return true;
 }
diff --git a/tests/main.c b/tests/main.c
index bef2e37..7386469 100644
--- a/tests/main.c
+++ b/tests/main.c
@@ -9,14 +9,26 @@
 #include "tests.h"
 #include "bfstd.h"
 #include "color.h"
+#include "thread.h"
 #include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 
+/** Result of the current test. */
+static thread_local bool pass;
+
+bool bfs_check_impl(bool result) {
+	pass &= result;
+	return result;
+}
+
+/** Unit test function type. */
+typedef void test_fn(void);
+
 /**
- * Test context.
+ * Global test context.
  */
 struct test_ctx {
 	/** Number of command line arguments. */
@@ -80,7 +92,10 @@ static bool should_run(const struct test_ctx *ctx, const char *test) {
 /** Run a test if it's enabled. */
 static void run_test(struct test_ctx *ctx, const char *test, test_fn *fn) {
 	if (should_run(ctx, test)) {
-		if (fn()) {
+		pass = true;
+		fn();
+
+		if (pass) {
 			cfprintf(ctx->cout, "${grn}[PASS]${rs} ${bld}%s${rs}\n", test);
 		} else {
 			cfprintf(ctx->cout, "${red}[FAIL]${rs} ${bld}%s${rs}\n", test);
diff --git a/tests/sighook.c b/tests/sighook.c
index b938edf..f1c4c27 100644
--- a/tests/sighook.c
+++ b/tests/sighook.c
@@ -52,44 +52,37 @@ static int block_signal(int sig, sigset_t *old) {
 	return 0;
 }
 
-bool check_sighook(void) {
-	bool ret = true;
-
+void check_sighook(void) {
 	struct sighook *hook = sighook(SIGALRM, alrm_hook, NULL, SH_CONTINUE);
-	ret &= bfs_echeck(hook, "sighook(SIGALRM)");
-	if (!ret) {
-		goto done;
+	if (!bfs_echeck(hook, "sighook(SIGALRM)")) {
+		return;
 	}
 
 	// Create a timer that sends SIGALRM every 100 microseconds
 	struct itimerval ival = {0};
 	ival.it_value.tv_usec = 100;
 	ival.it_interval.tv_usec = 100;
-	ret &= bfs_echeck(setitimer(ITIMER_REAL, &ival, NULL) == 0);
-	if (!ret) {
+	if (!bfs_echeck(setitimer(ITIMER_REAL, &ival, NULL) == 0)) {
 		goto unhook;
 	}
 
 	// Create a background thread to receive signals
 	pthread_t thread;
-	ret &= bfs_echeck(thread_create(&thread, NULL, hook_thread, NULL) == 0);
-	if (!ret) {
+	if (!bfs_echeck(thread_create(&thread, NULL, hook_thread, NULL) == 0)) {
 		goto untime;
 	}
 
 	// Block SIGALRM in this thread so the handler runs concurrently with
 	// sighook()/sigunhook()
 	sigset_t mask;
-	ret &= bfs_echeck(block_signal(SIGALRM, &mask) == 0);
-	if (!ret) {
+	if (!bfs_echeck(block_signal(SIGALRM, &mask) == 0)) {
 		goto untime;
 	}
 
 	// Rapidly register/unregister SIGALRM hooks
 	while (load(&count, relaxed) < 1000) {
 		struct sighook *next = sighook(SIGALRM, alrm_hook, NULL, SH_CONTINUE);
-		ret &= bfs_echeck(next, "sighook(SIGALRM)");
-		if (!ret) {
+		if (!bfs_echeck(next, "sighook(SIGALRM)")) {
 			break;
 		}
 
@@ -106,18 +99,12 @@ bool check_sighook(void) {
 
 	// Restore the old signal mask
 	errno = pthread_sigmask(SIG_SETMASK, &mask, NULL);
-	ret &= bfs_echeck(errno == 0, "pthread_sigmask()");
+	bfs_echeck(errno == 0, "pthread_sigmask()");
 untime:
 	// Stop the timer
 	ival.it_value.tv_usec = 0;
-	ret &= bfs_echeck(setitimer(ITIMER_REAL, &ival, NULL) == 0);
-	if (!ret) {
-		goto unhook;
-	}
-
+	bfs_echeck(setitimer(ITIMER_REAL, &ival, NULL) == 0);
 unhook:
 	// Unregister the SIGALRM hook
 	sigunhook(hook);
-done:
-	return ret;
 }
diff --git a/tests/tests.h b/tests/tests.h
index 2958fe1..01d6096 100644
--- a/tests/tests.h
+++ b/tests/tests.h
@@ -12,47 +12,41 @@
 #include "bfstd.h"
 #include "diag.h"
 
-/** Unit test function type. */
-typedef bool test_fn(void);
-
 /** Memory allocation tests. */
-bool check_alloc(void);
+void check_alloc(void);
 
 /** Standard library wrapper tests. */
-bool check_bfstd(void);
+void check_bfstd(void);
 
 /** Bit manipulation tests. */
-bool check_bit(void);
+void check_bit(void);
 
 /** I/O queue tests. */
-bool check_ioq(void);
+void check_ioq(void);
 
 /** Linked list tests. */
-bool check_list(void);
+void check_list(void);
 
 /** Signal hook tests. */
-bool check_sighook(void);
+void check_sighook(void);
 
 /** Trie tests. */
-bool check_trie(void);
+void check_trie(void);
 
 /** Process spawning tests. */
-bool check_xspawn(void);
+void check_xspawn(void);
 
 /** Time tests. */
-bool check_xtime(void);
+void check_xtime(void);
 
-/** Don't ignore the bfs_check() return value. */
-attr(nodiscard)
-static inline bool bfs_check(bool ret) {
-	return ret;
-}
+/** Record a single check and return the result. */
+bool bfs_check_impl(bool result);
 
 /**
  * Check a condition, logging a message on failure but continuing.
  */
 #define bfs_check(...) \
-	bfs_check(bfs_check_(#__VA_ARGS__, __VA_ARGS__, "", ""))
+	bfs_check_impl(bfs_check_(#__VA_ARGS__, __VA_ARGS__, "", ""))
 
 #define bfs_check_(str, cond, format, ...) \
 	((cond) ? true : (bfs_diag( \
@@ -65,7 +59,7 @@ static inline bool bfs_check(bool ret) {
  * Check a condition, logging the current error string on failure.
  */
 #define bfs_echeck(...) \
-	bfs_echeck_(#__VA_ARGS__, __VA_ARGS__, "", errstr())
+	bfs_check_impl(bfs_echeck_(#__VA_ARGS__, __VA_ARGS__, "", errstr()))
 
 #define bfs_echeck_(str, cond, format, ...) \
 	((cond) ? true : (bfs_diag( \
diff --git a/tests/trie.c b/tests/trie.c
index ebaae5d..f380613 100644
--- a/tests/trie.c
+++ b/tests/trie.c
@@ -39,14 +39,12 @@ static const char *keys[] = {
 
 static const size_t nkeys = countof(keys);
 
-bool check_trie(void) {
-	bool ret = true;
-
+void check_trie(void) {
 	struct trie trie;
 	trie_init(&trie);
 
 	for (size_t i = 0; i < nkeys; ++i) {
-		ret &= bfs_check(!trie_find_str(&trie, keys[i]));
+		bfs_check(!trie_find_str(&trie, keys[i]));
 
 		const char *prefix = NULL;
 		for (size_t j = 0; j < i; ++j) {
@@ -60,37 +58,37 @@ bool check_trie(void) {
 		struct trie_leaf *leaf = trie_find_prefix(&trie, keys[i]);
 		if (prefix) {
 			bfs_verify(leaf);
-			ret &= bfs_check(strcmp(prefix, leaf->key) == 0);
+			bfs_check(strcmp(prefix, leaf->key) == 0);
 		} else {
-			ret &= bfs_check(!leaf);
+			bfs_check(!leaf);
 		}
 
 		leaf = trie_insert_str(&trie, keys[i]);
 		bfs_verify(leaf);
-		ret &= bfs_check(strcmp(keys[i], leaf->key) == 0);
-		ret &= bfs_check(leaf->length == strlen(keys[i]) + 1);
+		bfs_check(strcmp(keys[i], leaf->key) == 0);
+		bfs_check(leaf->length == strlen(keys[i]) + 1);
 	}
 
 	{
 		size_t i = 0;
 		for_trie (leaf, &trie) {
-			ret &= bfs_check(leaf == trie_find_str(&trie, keys[i]));
-			ret &= bfs_check(!leaf->prev || leaf->prev->next == leaf);
-			ret &= bfs_check(!leaf->next || leaf->next->prev == leaf);
+			bfs_check(leaf == trie_find_str(&trie, keys[i]));
+			bfs_check(!leaf->prev || leaf->prev->next == leaf);
+			bfs_check(!leaf->next || leaf->next->prev == leaf);
 			++i;
 		}
-		ret &= bfs_check(i == nkeys);
+		bfs_check(i == nkeys);
 	}
 
 	for (size_t i = 0; i < nkeys; ++i) {
 		struct trie_leaf *leaf = trie_find_str(&trie, keys[i]);
 		bfs_verify(leaf);
-		ret &= bfs_check(strcmp(keys[i], leaf->key) == 0);
-		ret &= bfs_check(leaf->length == strlen(keys[i]) + 1);
+		bfs_check(strcmp(keys[i], leaf->key) == 0);
+		bfs_check(leaf->length == strlen(keys[i]) + 1);
 
 		trie_remove(&trie, leaf);
 		leaf = trie_find_str(&trie, keys[i]);
-		ret &= bfs_check(!leaf);
+		bfs_check(!leaf);
 
 		const char *postfix = NULL;
 		for (size_t j = i + 1; j < nkeys; ++j) {
@@ -104,14 +102,14 @@ bool check_trie(void) {
 		leaf = trie_find_postfix(&trie, keys[i]);
 		if (postfix) {
 			bfs_verify(leaf);
-			ret &= bfs_check(strcmp(postfix, leaf->key) == 0);
+			bfs_check(strcmp(postfix, leaf->key) == 0);
 		} else {
-			ret &= bfs_check(!leaf);
+			bfs_check(!leaf);
 		}
 	}
 
 	for_trie (leaf, &trie) {
-		ret &= bfs_check(false, "trie should be empty");
+		bfs_check(false, "trie should be empty");
 	}
 
 	// This tests the "jump" node handling on 32-bit platforms
@@ -120,18 +118,17 @@ bool check_trie(void) {
 	bfs_verify(longstr);
 
 	memset(longstr, 0xAC, longsize);
-	ret &= bfs_check(!trie_find_mem(&trie, longstr, longsize));
-	ret &= bfs_check(trie_insert_mem(&trie, longstr, longsize));
+	bfs_check(!trie_find_mem(&trie, longstr, longsize));
+	bfs_check(trie_insert_mem(&trie, longstr, longsize));
 
 	memset(longstr + longsize / 2, 0xAB, longsize / 2);
-	ret &= bfs_check(!trie_find_mem(&trie, longstr, longsize));
-	ret &= bfs_check(trie_insert_mem(&trie, longstr, longsize));
+	bfs_check(!trie_find_mem(&trie, longstr, longsize));
+	bfs_check(trie_insert_mem(&trie, longstr, longsize));
 
 	memset(longstr, 0xAA, longsize / 2);
-	ret &= bfs_check(!trie_find_mem(&trie, longstr, longsize));
-	ret &= bfs_check(trie_insert_mem(&trie, longstr, longsize));
+	bfs_check(!trie_find_mem(&trie, longstr, longsize));
+	bfs_check(trie_insert_mem(&trie, longstr, longsize));
 
 	free(longstr);
 	trie_destroy(&trie);
-	return ret;
 }
diff --git a/tests/xspawn.c b/tests/xspawn.c
index f48e220..d77a078 100644
--- a/tests/xspawn.c
+++ b/tests/xspawn.c
@@ -50,13 +50,10 @@ fail:
 }
 
 /** Check that we resolve executables in $PATH correctly. */
-static bool check_use_path(bool use_posix) {
-	bool ret = true;
-
+static void check_use_path(bool use_posix) {
 	struct bfs_spawn spawn;
-	ret &= bfs_echeck(bfs_spawn_init(&spawn) == 0);
-	if (!ret) {
-		goto out;
+	if (!bfs_echeck(bfs_spawn_init(&spawn) == 0)) {
+		return;
 	}
 
 	spawn.flags |= BFS_SPAWN_USE_PATH;
@@ -64,19 +61,18 @@ static bool check_use_path(bool use_posix) {
 		spawn.flags &= ~BFS_SPAWN_USE_POSIX;
 	}
 
-	ret &= bfs_echeck(bfs_spawn_addopen(&spawn, 10, "bin", O_RDONLY | O_DIRECTORY, 0) == 0);
-	ret &= bfs_echeck(bfs_spawn_adddup2(&spawn, 10, 11) == 0);
-	ret &= bfs_echeck(bfs_spawn_addclose(&spawn, 10) == 0);
-	ret &= bfs_echeck(bfs_spawn_addfchdir(&spawn, 11) == 0);
-	ret &= bfs_echeck(bfs_spawn_addclose(&spawn, 11) == 0);
-	if (!ret) {
+	bool init = bfs_echeck(bfs_spawn_addopen(&spawn, 10, "bin", O_RDONLY | O_DIRECTORY, 0) == 0)
+		&& bfs_echeck(bfs_spawn_adddup2(&spawn, 10, 11) == 0)
+		&& bfs_echeck(bfs_spawn_addclose(&spawn, 10) == 0)
+		&& bfs_echeck(bfs_spawn_addfchdir(&spawn, 11) == 0)
+		&& bfs_echeck(bfs_spawn_addclose(&spawn, 11) == 0);
+	if (!init) {
 		goto destroy;
 	}
 
 	// Check that $PATH is resolved in the parent's environment
-	char **envp;
-	ret &= bfs_echeck(envp = envdup());
-	if (!ret) {
+	char **envp = envdup();
+	if (!bfs_echeck(envp, "envdup()")) {
 		goto destroy;
 	}
 
@@ -84,44 +80,41 @@ static bool check_use_path(bool use_posix) {
 	char *old_path = getenv("PATH");
 	dchar *new_path = NULL;
 	if (old_path) {
-		ret &= bfs_echeck(old_path = strdup(old_path));
-		if (!ret) {
+		old_path = strdup(old_path);
+		if (!bfs_echeck(old_path, "strdup()")) {
 			goto env;
 		}
 		new_path = dstrprintf("tests:%s", old_path);
 	} else {
 		new_path = dstrdup("tests");
 	}
-	ret &= bfs_check(new_path);
-	if (!ret) {
+	if (!bfs_check(new_path)) {
 		goto path;
 	}
 
-	ret &= bfs_echeck(setenv("PATH", new_path, true) == 0);
-	if (!ret) {
+	if (!bfs_echeck(setenv("PATH", new_path, true) == 0)) {
 		goto path;
 	}
 
 	char *argv[] = {"xspawnee", old_path, NULL};
 	pid_t pid = bfs_spawn("xspawnee", &spawn, argv, envp);
-	ret &= bfs_echeck(pid >= 0, "bfs_spawn()");
-	if (!ret) {
+	if (!bfs_echeck(pid >= 0, "bfs_spawn()")) {
 		goto unset;
 	}
 
 	int wstatus;
-	ret &= bfs_echeck(xwaitpid(pid, &wstatus, 0) == pid)
+	bool exited = bfs_echeck(xwaitpid(pid, &wstatus, 0) == pid)
 		&& bfs_check(WIFEXITED(wstatus));
-	if (ret) {
+	if (exited) {
 		int wexit = WEXITSTATUS(wstatus);
-		ret &= bfs_check(wexit == EXIT_SUCCESS, "xspawnee: exit(%d)", wexit);
+		bfs_check(wexit == EXIT_SUCCESS, "xspawnee: exit(%d)", wexit);
 	}
 
 unset:
 	if (old_path) {
-		ret &= bfs_echeck(setenv("PATH", old_path, true) == 0);
+		bfs_echeck(setenv("PATH", old_path, true) == 0);
 	} else {
-		ret &= bfs_echeck(unsetenv("PATH") == 0);
+		bfs_echeck(unsetenv("PATH") == 0);
 	}
 path:
 	dstrfree(new_path);
@@ -132,19 +125,14 @@ env:
 	}
 	free(envp);
 destroy:
-	ret &= bfs_echeck(bfs_spawn_destroy(&spawn) == 0);
-out:
-	return ret;
+	bfs_echeck(bfs_spawn_destroy(&spawn) == 0);
 }
 
 /** Check path resolution of non-existent executables. */
-static bool check_enoent(bool use_posix) {
-	bool ret = true;
-
+static void check_enoent(bool use_posix) {
 	struct bfs_spawn spawn;
-	ret &= bfs_echeck(bfs_spawn_init(&spawn) == 0);
-	if (!ret) {
-		goto out;
+	if (!bfs_echeck(bfs_spawn_init(&spawn) == 0)) {
+		return;
 	}
 
 	spawn.flags |= BFS_SPAWN_USE_PATH;
@@ -154,46 +142,37 @@ static bool check_enoent(bool use_posix) {
 
 	char *argv[] = {"eW6f5RM9Qi", NULL};
 	pid_t pid = bfs_spawn("eW6f5RM9Qi", &spawn, argv, NULL);
-	ret &= bfs_echeck(pid < 0 && errno == ENOENT, "bfs_spawn()");
+	bfs_echeck(pid < 0 && errno == ENOENT, "bfs_spawn()");
 
-	ret &= bfs_echeck(bfs_spawn_destroy(&spawn) == 0);
-out:
-	return ret;
+	bfs_echeck(bfs_spawn_destroy(&spawn) == 0);
 }
 
-static bool check_resolve(void) {
-	bool ret = true;
+static void check_resolve(void) {
 	char *exe;
 
 	exe = bfs_spawn_resolve("sh");
-	ret &= bfs_echeck(exe, "bfs_spawn_resolve('sh')");
+	bfs_echeck(exe, "bfs_spawn_resolve('sh')");
 	free(exe);
 
 	exe = bfs_spawn_resolve("/bin/sh");
-	ret &= bfs_echeck(exe && strcmp(exe, "/bin/sh") == 0);
+	bfs_echeck(exe && strcmp(exe, "/bin/sh") == 0);
 	free(exe);
 
 	exe = bfs_spawn_resolve("bin/tests/xspawnee");
-	ret &= bfs_echeck(exe && strcmp(exe, "bin/tests/xspawnee") == 0);
+	bfs_echeck(exe && strcmp(exe, "bin/tests/xspawnee") == 0);
 	free(exe);
 
-	ret &= bfs_echeck(!bfs_spawn_resolve("eW6f5RM9Qi") && errno == ENOENT);
-
-	ret &= bfs_echeck(!bfs_spawn_resolve("bin/eW6f5RM9Qi") && errno == ENOENT);
+	bfs_echeck(!bfs_spawn_resolve("eW6f5RM9Qi") && errno == ENOENT);
 
-	return ret;
+	bfs_echeck(!bfs_spawn_resolve("bin/eW6f5RM9Qi") && errno == ENOENT);
 }
 
-bool check_xspawn(void) {
-	bool ret = true;
-
-	ret &= check_use_path(true);
-	ret &= check_use_path(false);
-
-	ret &= check_enoent(true);
-	ret &= check_enoent(false);
+void check_xspawn(void) {
+	check_use_path(true);
+	check_use_path(false);
 
-	ret &= check_resolve();
+	check_enoent(true);
+	check_enoent(false);
 
-	return ret;
+	check_resolve();
 }
diff --git a/tests/xtime.c b/tests/xtime.c
index 1907e26..ea9e372 100644
--- a/tests/xtime.c
+++ b/tests/xtime.c
@@ -39,35 +39,31 @@ static bool check_one_xgetdate(const char *str, int error, time_t expected) {
 }
 
 /** xgetdate() tests. */
-static bool check_xgetdate(void) {
-	bool ret = true;
-
-	ret &= check_one_xgetdate("", EINVAL, 0);
-	ret &= check_one_xgetdate("????", EINVAL, 0);
-	ret &= check_one_xgetdate("1991", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-??", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12-", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12-??", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12-14", 0, 692668800);
-	ret &= check_one_xgetdate("1991-12-14-", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12-14T", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12-14T??", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12-14T10", 0, 692704800);
-	ret &= check_one_xgetdate("1991-12-14T10:??", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12-14T10:11", 0, 692705460);
-	ret &= check_one_xgetdate("1991-12-14T10:11:??", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12-14T10:11:12", 0, 692705472);
-	ret &= check_one_xgetdate("1991-12-14T10Z", 0, 692704800);
-	ret &= check_one_xgetdate("1991-12-14T10:11Z", 0, 692705460);
-	ret &= check_one_xgetdate("1991-12-14T10:11:12Z", 0, 692705472);
-	ret &= check_one_xgetdate("1991-12-14T10:11:12?", EINVAL, 0);
-	ret &= check_one_xgetdate("1991-12-14T03-07", 0, 692704800);
-	ret &= check_one_xgetdate("1991-12-14T06:41-03:30", 0, 692705460);
-	ret &= check_one_xgetdate("1991-12-14T03:11:12-07:00", 0, 692705472);
-	ret &= check_one_xgetdate("19911214 031112-0700", 0, 692705472);;
-
-	return ret;
+static void check_xgetdate(void) {
+	check_one_xgetdate("", EINVAL, 0);
+	check_one_xgetdate("????", EINVAL, 0);
+	check_one_xgetdate("1991", EINVAL, 0);
+	check_one_xgetdate("1991-??", EINVAL, 0);
+	check_one_xgetdate("1991-12", EINVAL, 0);
+	check_one_xgetdate("1991-12-", EINVAL, 0);
+	check_one_xgetdate("1991-12-??", EINVAL, 0);
+	check_one_xgetdate("1991-12-14", 0, 692668800);
+	check_one_xgetdate("1991-12-14-", EINVAL, 0);
+	check_one_xgetdate("1991-12-14T", EINVAL, 0);
+	check_one_xgetdate("1991-12-14T??", EINVAL, 0);
+	check_one_xgetdate("1991-12-14T10", 0, 692704800);
+	check_one_xgetdate("1991-12-14T10:??", EINVAL, 0);
+	check_one_xgetdate("1991-12-14T10:11", 0, 692705460);
+	check_one_xgetdate("1991-12-14T10:11:??", EINVAL, 0);
+	check_one_xgetdate("1991-12-14T10:11:12", 0, 692705472);
+	check_one_xgetdate("1991-12-14T10Z", 0, 692704800);
+	check_one_xgetdate("1991-12-14T10:11Z", 0, 692705460);
+	check_one_xgetdate("1991-12-14T10:11:12Z", 0, 692705472);
+	check_one_xgetdate("1991-12-14T10:11:12?", EINVAL, 0);
+	check_one_xgetdate("1991-12-14T03-07", 0, 692704800);
+	check_one_xgetdate("1991-12-14T06:41-03:30", 0, 692705460);
+	check_one_xgetdate("1991-12-14T03:11:12-07:00", 0, 692705472);
+	check_one_xgetdate("19911214 031112-0700", 0, 692705472);;
 }
 
 #define TM_FORMAT "%04d-%02d-%02d %02d:%02d:%02d (%d/7, %d/365%s)"
@@ -92,11 +88,9 @@ static bool check_one_xmktime(time_t expected) {
 }
 
 /** xmktime() tests. */
-static bool check_xmktime(void) {
-	bool ret = true;
-
+static void check_xmktime(void) {
 	for (time_t time = -10; time <= 10; ++time) {
-		ret &= check_one_xmktime(time);
+		check_one_xmktime(time);
 	}
 
 	// Attempt to trigger overflow (but don't test for it, since it's not mandatory)
@@ -111,12 +105,10 @@ static bool check_xmktime(void) {
 	};
 	time_t time;
 	xmktime(&tm, &time);
-
-	return ret;
 }
 
 /** Check one xtimegm() result. */
-static bool check_one_xtimegm(const struct tm *tm) {
+static void check_one_xtimegm(const struct tm *tm) {
 	struct tm tma = *tm, tmb = *tm;
 	time_t ta, tb;
 	ta = mktime(&tma);
@@ -124,43 +116,39 @@ static bool check_one_xtimegm(const struct tm *tm) {
 		tb = -1;
 	}
 
-	bool ret = true;
-	ret &= bfs_check(ta == tb, "%jd != %jd", (intmax_t)ta, (intmax_t)tb);
-	ret &= bfs_check(ta == -1 || tm_equal(&tma, &tmb));
+	bool pass = true;
+	pass &= bfs_check(ta == tb, "%jd != %jd", (intmax_t)ta, (intmax_t)tb);
+	if (ta != -1) {
+		pass &= bfs_check(tm_equal(&tma, &tmb));
+	}
 
-	if (!ret) {
+	if (!pass) {
 		bfs_diag("mktime():  " TM_FORMAT, TM_PRINTF(tma));
 		bfs_diag("xtimegm(): " TM_FORMAT, TM_PRINTF(tmb));
 		bfs_diag("(input):   " TM_FORMAT, TM_PRINTF(*tm));
 	}
-
-	return ret;
 }
 
 #if !BFS_HAS_TIMEGM
 /** Check an overflowing xtimegm() call. */
-static bool check_xtimegm_overflow(const struct tm *tm) {
+static void check_xtimegm_overflow(const struct tm *tm) {
 	struct tm copy = *tm;
 	time_t time = 123;
 
-	bool ret = true;
-	ret &= bfs_check(xtimegm(&copy, &time) == -1 && errno == EOVERFLOW);
-	ret &= bfs_check(tm_equal(&copy, tm));
-	ret &= bfs_check(time == 123);
+	bool pass = true;
+	pass &= bfs_check(xtimegm(&copy, &time) == -1 && errno == EOVERFLOW);
+	pass &= bfs_check(tm_equal(&copy, tm));
+	pass &= bfs_check(time == 123);
 
-	if (!ret) {
+	if (!pass) {
 		bfs_diag("xtimegm(): " TM_FORMAT, TM_PRINTF(copy));
 		bfs_diag("(input):   " TM_FORMAT, TM_PRINTF(*tm));
 	}
-
-	return ret;
 }
 #endif
 
 /** xtimegm() tests. */
-static bool check_xtimegm(void) {
-	bool ret = true;
-
+static void check_xtimegm(void) {
 	struct tm tm = {
 		.tm_isdst = -1,
 	};
@@ -172,24 +160,20 @@ static bool check_xtimegm(void) {
 	for (tm.tm_hour =  -1; tm.tm_hour <=  24; tm.tm_hour +=  5)
 	for (tm.tm_min  =  -1; tm.tm_min  <=  60; tm.tm_min  += 31)
 	for (tm.tm_sec  = -60; tm.tm_sec  <= 120; tm.tm_sec  +=  5) {
-		ret &= check_one_xtimegm(&tm);
+		check_one_xtimegm(&tm);
 	}
 
 #if !BFS_HAS_TIMEGM
 	// Check integer overflow cases
-	ret &= check_xtimegm_overflow(&(struct tm) { .tm_sec = INT_MAX, .tm_min = INT_MAX });
-	ret &= check_xtimegm_overflow(&(struct tm) { .tm_min = INT_MAX, .tm_hour = INT_MAX });
-	ret &= check_xtimegm_overflow(&(struct tm) { .tm_hour = INT_MAX, .tm_mday = INT_MAX });
-	ret &= check_xtimegm_overflow(&(struct tm) { .tm_mon = INT_MAX, .tm_year = INT_MAX });
+	check_xtimegm_overflow(&(struct tm) { .tm_sec = INT_MAX, .tm_min = INT_MAX });
+	check_xtimegm_overflow(&(struct tm) { .tm_min = INT_MAX, .tm_hour = INT_MAX });
+	check_xtimegm_overflow(&(struct tm) { .tm_hour = INT_MAX, .tm_mday = INT_MAX });
+	check_xtimegm_overflow(&(struct tm) { .tm_mon = INT_MAX, .tm_year = INT_MAX });
 #endif
-
-	return ret;
 }
 
-bool check_xtime(void) {
-	bool ret = true;
-	ret &= check_xgetdate();
-	ret &= check_xmktime();
-	ret &= check_xtimegm();
-	return ret;
+void check_xtime(void) {
+	check_xgetdate();
+	check_xmktime();
+	check_xtimegm();
 }
-- 
cgit v1.2.3