summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile27
-rw-r--r--tests/alloc.c6
-rw-r--r--tests/bfstd.c5
-rw-r--r--tests/bit.c5
-rw-r--r--tests/main.c106
-rw-r--r--tests/tests.h26
-rw-r--r--tests/trie.c5
-rw-r--r--tests/xtime.c (renamed from tests/xtimegm.c)9
8 files changed, 166 insertions, 23 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 66af797..34c7f37 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -269,32 +269,39 @@ LIBBFS := \
# The main executable
$(BIN)/bfs: $(OBJ)/src/main.o $(LIBBFS)
-# Standalone unit tests
-UNITS := alloc bfstd bit trie xtimegm
-UNIT_TESTS := $(UNITS:%=$(BIN)/tests/%)
-UNIT_CHECKS := $(UNITS:%=check-%)
-
# Testing utilities
TEST_UTILS := $(BIN)/tests/mksock $(BIN)/tests/xtouch
-TESTS := $(UNIT_TESTS) $(TEST_UTILS)
+$(BIN)/tests/mksock: $(OBJ)/tests/mksock.o $(LIBBFS)
+
+$(BIN)/tests/xtouch: $(OBJ)/tests/xtouch.o $(LIBBFS)
+
+# All test binaries
+TESTS := $(BIN)/tests/units $(TEST_UTILS)
+
+$(BIN)/tests/units: \
+ $(OBJ)/tests/alloc.o \
+ $(OBJ)/tests/bfstd.o \
+ $(OBJ)/tests/bit.o \
+ $(OBJ)/tests/main.o \
+ $(OBJ)/tests/trie.o \
+ $(OBJ)/tests/xtime.o \
+ $(LIBBFS)
tests: $(TESTS)
.PHONY: tests
-$(TESTS): $(BIN)/tests/%: $(OBJ)/tests/%.o $(LIBBFS)
-
# The different search strategies that we test
STRATEGIES := bfs dfs ids eds
STRATEGY_CHECKS := $(STRATEGIES:%=check-%)
# All the different checks we run
-CHECKS := $(UNIT_CHECKS) $(STRATEGY_CHECKS)
+CHECKS := check-units $(STRATEGY_CHECKS)
check: $(CHECKS)
.PHONY: check $(CHECKS)
-$(UNIT_CHECKS): check-%: $(BIN)/tests/%
+check-units: $(BIN)/tests/units
$<
JOBS := $(filter -j%,$(MAKEFLAGS))
diff --git a/tests/alloc.c b/tests/alloc.c
index 37b70bf..e14f131 100644
--- a/tests/alloc.c
+++ b/tests/alloc.c
@@ -1,13 +1,14 @@
// Copyright © Tavian Barnes <tavianator@tavianator.com>
// SPDX-License-Identifier: 0BSD
+#include "tests.h"
#include "../src/alloc.h"
#include "../src/diag.h"
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
-int main(void) {
+bool check_alloc(void) {
// Check sizeof_flex()
struct flexible {
alignas(64) int foo[8];
@@ -44,6 +45,5 @@ int main(void) {
}
varena_destroy(&varena);
-
- return EXIT_SUCCESS;
+ return true;
}
diff --git a/tests/bfstd.c b/tests/bfstd.c
index c386279..d385c6b 100644
--- a/tests/bfstd.c
+++ b/tests/bfstd.c
@@ -1,6 +1,7 @@
// Copyright © Tavian Barnes <tavianator@tavianator.com>
// SPDX-License-Identifier: 0BSD
+#include "tests.h"
#include "../src/bfstd.h"
#include "../src/config.h"
#include "../src/diag.h"
@@ -34,7 +35,7 @@ static void check_wordesc(const char *str, const char *exp, enum wesc_flags flag
bfs_verify(strcmp(buf, exp) == 0, "wordesc(%s) == %s (!= %s)", str, buf, exp);
}
-int main(void) {
+bool check_bfstd(void) {
// Try to set a UTF-8 locale
if (!setlocale(LC_ALL, "C.UTF-8")) {
setlocale(LC_ALL, "");
@@ -69,5 +70,5 @@ int main(void) {
check_wordesc("\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80", WESC_SHELL | WESC_TTY);
}
- return EXIT_SUCCESS;
+ return true;
}
diff --git a/tests/bit.c b/tests/bit.c
index f9071be..1c6a4de 100644
--- a/tests/bit.c
+++ b/tests/bit.c
@@ -1,6 +1,7 @@
// Copyright © Tavian Barnes <tavianator@tavianator.com>
// SPDX-License-Identifier: 0BSD
+#include "tests.h"
#include "../src/bit.h"
#include "../src/diag.h"
#include <limits.h>
@@ -54,7 +55,7 @@ bfs_static_assert(INTMAX_MAX == IWIDTH_MAX(INTMAX_WIDTH));
#define verify_eq(a, b) \
bfs_verify((a) == (b), "(0x%jX) %s != %s (0x%jX)", (uintmax_t)(a), #a, #b, (uintmax_t)(b))
-int main(void) {
+bool check_bit(void) {
verify_eq(bswap((uint8_t)0x12), 0x12);
verify_eq(bswap((uint16_t)0x1234), 0x3412);
verify_eq(bswap((uint32_t)0x12345678), 0x78563412);
@@ -121,5 +122,5 @@ int main(void) {
bfs_verify(!has_single_bit(UINT32_MAX));
bfs_verify(has_single_bit((uint32_t)1 << (UINT_WIDTH - 1)));
- return EXIT_SUCCESS;
+ return true;
}
diff --git a/tests/main.c b/tests/main.c
new file mode 100644
index 0000000..b7292b4
--- /dev/null
+++ b/tests/main.c
@@ -0,0 +1,106 @@
+// Copyright © Tavian Barnes <tavianator@tavianator.com>
+// SPDX-License-Identifier: 0BSD
+
+/**
+ * Entry point for unit tests.
+ */
+
+#include "tests.h"
+#include "../src/bfstd.h"
+#include "../src/color.h"
+#include "../src/config.h"
+#include "../src/diag.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Test context.
+ */
+struct test_ctx {
+ /** Number of command line arguments. */
+ int argc;
+ /** The arguments themselves. */
+ char **argv;
+
+ /** Parsed colors. */
+ struct colors *colors;
+ /** Colorized output stream. */
+ CFILE *cout;
+
+ /** Eventual exit status. */
+ int ret;
+};
+
+/** Initialize the test context. */
+static int test_init(struct test_ctx *ctx, int argc, char **argv) {
+ ctx->argc = argc;
+ ctx->argv = argv;
+
+ ctx->colors = parse_colors();
+ ctx->cout = cfwrap(stdout, ctx->colors, false);
+ if (!ctx->cout) {
+ ctx->ret = EXIT_FAILURE;
+ return -1;
+ }
+
+ ctx->ret = EXIT_SUCCESS;
+ return 0;
+}
+
+/** Finalize the test context. */
+static int test_fini(struct test_ctx *ctx) {
+ if (ctx->cout) {
+ cfclose(ctx->cout);
+ }
+
+ free_colors(ctx->colors);
+
+ return ctx->ret;
+}
+
+/** Check if a test case is enabled for this run. */
+static bool should_run(const struct test_ctx *ctx, const char *test) {
+ // Run all tests by default
+ if (ctx->argc < 2) {
+ return true;
+ }
+
+ // With args, run only specified tests
+ for (int i = 1; i < ctx->argc; ++i) {
+ if (strcmp(test, ctx->argv[i]) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/** 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()) {
+ cfprintf(ctx->cout, "${grn}[PASS]${rs} ${bld}%s${rs}\n", test);
+ } else {
+ cfprintf(ctx->cout, "${red}[FAIL]${rs} ${bld}%s${rs}\n", test);
+ ctx->ret = EXIT_FAILURE;
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+ struct test_ctx ctx;
+ if (test_init(&ctx, argc, argv) != 0) {
+ goto done;
+ }
+
+ run_test(&ctx, "alloc", check_alloc);
+ run_test(&ctx, "bfstd", check_bfstd);
+ run_test(&ctx, "bit", check_bit);
+ run_test(&ctx, "trie", check_trie);
+ run_test(&ctx, "xtime", check_xtime);
+
+done:
+ return test_fini(&ctx);
+}
diff --git a/tests/tests.h b/tests/tests.h
new file mode 100644
index 0000000..34c58b7
--- /dev/null
+++ b/tests/tests.h
@@ -0,0 +1,26 @@
+// Copyright © Tavian Barnes <tavianator@tavianator.com>
+// SPDX-License-Identifier: 0BSD
+
+/**
+ * Unit tests.
+ */
+
+#include "../src/config.h"
+
+/** Unit test function type. */
+typedef bool test_fn(void);
+
+/** Memory allocation tests. */
+bool check_alloc(void);
+
+/** Standard library wrapper tests. */
+bool check_bfstd(void);
+
+/** Bit manipulation tests. */
+bool check_bit(void);
+
+/** Trie tests. */
+bool check_trie(void);
+
+/** Time tests. */
+bool check_xtime(void);
diff --git a/tests/trie.c b/tests/trie.c
index 656fd85..f94d7c8 100644
--- a/tests/trie.c
+++ b/tests/trie.c
@@ -1,6 +1,7 @@
// Copyright © Tavian Barnes <tavianator@tavianator.com>
// SPDX-License-Identifier: 0BSD
+#include "tests.h"
#include "../src/trie.h"
#include "../src/config.h"
#include "../src/diag.h"
@@ -38,7 +39,7 @@ const char *keys[] = {
const size_t nkeys = countof(keys);
-int main(void) {
+bool check_trie(void) {
struct trie trie;
trie_init(&trie);
@@ -130,5 +131,5 @@ int main(void) {
free(longstr);
trie_destroy(&trie);
- return EXIT_SUCCESS;
+ return true;
}
diff --git a/tests/xtimegm.c b/tests/xtime.c
index 973b2eb..53ecbc4 100644
--- a/tests/xtimegm.c
+++ b/tests/xtime.c
@@ -1,6 +1,7 @@
// Copyright © Tavian Barnes <tavianator@tavianator.com>
// SPDX-License-Identifier: 0BSD
+#include "tests.h"
#include "../src/xtime.h"
#include "../src/config.h"
#include <stdint.h>
@@ -48,10 +49,10 @@ static void tm_print(FILE *file, const struct tm *tm) {
tm->tm_isdst ? (tm->tm_isdst < 0 ? " (DST?)" : " (DST)") : "");
}
-int main(void) {
+bool check_xtime(void) {
if (setenv("TZ", "UTC0", true) != 0) {
perror("setenv()");
- return EXIT_FAILURE;
+ return false;
}
struct tm tm = {
@@ -86,9 +87,9 @@ int main(void) {
if (fail) {
printf("Input: ");
tm_print(stdout, &tm);
- return EXIT_FAILURE;
+ return false;
}
}
- return EXIT_SUCCESS;
+ return true;
}