#ifndef _UNITTEST_H #define _UNITTEST_H #include struct unittest { const char *name; int (*fn)(void *ctx); }; #define UNITTEST(_fn) __attribute__((section("unittests"))) \ static struct unittest _fn ## _desc = { \ .name = #_fn, \ .fn = _fn, \ } extern struct unittest __start_unittests; extern struct unittest __stop_unittests; #define unittest_foreach(_t) \ for ((_t) = &__start_unittests; (_t) < &__stop_unittests; (_t)++) struct unittest_ctx { int keep_going:1; int verbose:1; void *ctx; }; static inline int unittests_run(struct unittest_ctx *ctx) { struct unittest *t; int err, ret = 0; unittest_foreach(t) { if (ctx->verbose) { printf("%-40s\t", t->name); fflush(stdout); } err = t->fn(ctx->ctx); if (!err) { if (ctx->verbose) printf("pass\n"); continue; } if (!ctx->verbose) { printf("%-40s\t", t->name); fflush(stdout); } printf("\n%40s\tFAIL\n", ""); if (!ctx->keep_going) return err; else if (!ret) ret = err; } return ret; } #define unittest_eq(_a, _b) if ((_a) != (_b)) { \ printf("\n\t%s == %s (%lld != %lld)", \ #_a, #_b, (long long)(_a), (long long)(_b)); \ return -1; \ } #endif /* _UNITTEST_H */