/* ptest.h - Richard Lupton 2025 */ #ifndef PTEST_H #define PTEST_H #ifdef PTEST_TYPEDEFS typedef struct ptest_ctx ptest_ctx; typedef struct ptest_test ptest_test; #endif #ifndef ptest_emit #include #define ptest_emit(...) printf(__VA_ARGS__) #endif #define ptest_error(t, ...) do { \ ptest_emit("%s: ", (t)->name); \ ptest_emit(__VA_ARGS__); \ ptest_mark_failed(t); \ } while (0) #define ptest_diagnostic(t, ...) do { \ if (t->failed) ptest_emit(__VA_ARGS__); \ } while (0) #define PTEST_ANSI_BOLD "\x1b[1m" #define PTEST_ANSI_RESET "\x1b[0m" #define PTEST_ANSI_GREEN "\x1b[32m" #define PTEST_ANSI_RED "\x1b[31m" #define PTEST_ANSI_DEFAULT_COLOUR "\x1b[39m" #define PTEST_OPT_ANSI_COLOURS 0x01 struct ptest_ctx { long passed; long failed; int opts; }; struct ptest_test { const char *name; int failed; }; static inline void ptest_mark_failed(struct ptest_test *t) { t->failed = 1; } static inline void ptest_run(struct ptest_ctx *pt, void (*test)(struct ptest_test *), const char *name) { struct ptest_test t = { .name = name, .failed = 0, }; test(&t); if (t.failed) { pt->failed++; } else { pt->passed++; } ptest_emit("%-75s ", name); if (pt->opts & PTEST_OPT_ANSI_COLOURS) { ptest_emit(PTEST_ANSI_BOLD); if (t.failed) { ptest_emit(PTEST_ANSI_RED); } else { ptest_emit(PTEST_ANSI_GREEN); } } ptest_emit("%s", t.failed ? "FAIL" : "PASS"); if (pt->opts & PTEST_OPT_ANSI_COLOURS) { ptest_emit(PTEST_ANSI_RESET); } ptest_emit("\n"); } #define ptest_run(r, test) ptest_run((r), (test), #test) static inline int ptest_summarise(const struct ptest_ctx *pt) { if (pt->opts & PTEST_OPT_ANSI_COLOURS) ptest_emit(PTEST_ANSI_BOLD); ptest_emit("\n\n"); ptest_emit("PASSED: "); if (pt->opts & PTEST_OPT_ANSI_COLOURS && pt->passed > 0) ptest_emit(PTEST_ANSI_GREEN); ptest_emit("%ld\n", pt->passed); if (pt->opts & PTEST_OPT_ANSI_COLOURS) ptest_emit(PTEST_ANSI_DEFAULT_COLOUR); ptest_emit("FAILED: "); if (pt->opts & PTEST_OPT_ANSI_COLOURS && pt->failed > 0) ptest_emit(PTEST_ANSI_RED); ptest_emit("%ld\n\n", pt->failed); if (pt->opts & PTEST_OPT_ANSI_COLOURS) ptest_emit(PTEST_ANSI_RESET); return pt->failed ? -1 : 0; } #endif