From: LeonardoBizzoni Date: Mon, 13 Oct 2025 10:15:44 +0000 (+0200) Subject: Testing functionality X-Git-Url: http://git.leonardobizzoni.com/?a=commitdiff_plain;h=0a89a43f0ee2aa8740bec14bf10e7f50ead5f84b;p=CBuild Testing functionality --- diff --git a/cbuild.h b/cbuild.h index 8538f96..13d0672 100644 --- a/cbuild.h +++ b/cbuild.h @@ -56,6 +56,7 @@ #endif #if !CPP +# define BOOL_DEFINED 1 # if __STDC_VERSION__ >= 199901L # include # else @@ -99,6 +100,14 @@ typedef enum {false, true} bool; typedef pid_t CB_ProcHandle; #endif +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_MAGENTA "\x1b[35m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_RESET "\x1b[0m" + #define internal static #ifndef _assert_break # if OS_WINDOWS @@ -107,7 +116,24 @@ typedef enum {false, true} bool; # define _assert_break() __builtin_trap() # endif #endif -#define Assert(COND) do { if (!(COND)) { _assert_break(); } } while (0) + + +internal void cb_assertion_break(const char *condition, + const char *file, int32_t line) { + _assert_break(); +} + +typedef void (*cb_assertion_handler_fn)(const char *condition, + const char *file, int32_t line); +internal cb_assertion_handler_fn cb_assertion_handler = cb_assertion_break; + +#define cb_assert(COND) \ + do { \ + if (!(COND)) { \ + cb_assertion_handler(#COND, __FILE__, __LINE__); \ + } \ + } while (0) + #define StackPush(Head, Nodeptr) \ LLPushFrontCustom((Head), (Head), (Nodeptr), next) #define StackPop(Head) (Head ? (Head = Head->next) : 0) @@ -215,7 +241,7 @@ enum { } \ (Dynarr)->Values = realloc((Dynarr)->Values, (Dynarr)->Capacity * \ sizeof((Dynarr)->Values[0])); \ - Assert((Dynarr)->Values); \ + cb_assert((Dynarr)->Values); \ } while(0) #define cb_dyn_push_custom(Dynarr, Node, Values, Count, Capacity) \ do { \ @@ -276,13 +302,6 @@ static char* cb_format(const char *format, ...) { } static void cb_print(CB_LogLevel level, const char *fmt, ...) { -#define ANSI_COLOR_RED "\x1b[31m" -#define ANSI_COLOR_GREEN "\x1b[32m" -#define ANSI_COLOR_YELLOW "\x1b[33m" -#define ANSI_COLOR_BLUE "\x1b[34m" -#define ANSI_COLOR_MAGENTA "\x1b[35m" -#define ANSI_COLOR_CYAN "\x1b[36m" -#define ANSI_COLOR_RESET "\x1b[0m" va_list args; switch (level) { case CB_LogLevel_Info: { @@ -302,13 +321,6 @@ static void cb_print(CB_LogLevel level, const char *fmt, ...) { va_start(args, fmt); printf("%s", _cb_format(fmt, args)); va_end(args); -#undef ANSI_COLOR_RED -#undef ANSI_COLOR_GREEN -#undef ANSI_COLOR_YELLOW -#undef ANSI_COLOR_BLUE -#undef ANSI_COLOR_MAGENTA -#undef ANSI_COLOR_CYAN -#undef ANSI_COLOR_RESET } static char* cb_getenv(char *varname) { @@ -352,7 +364,7 @@ static void cb_process_wait(CB_Process *proc) { CloseHandle(proc->handle); #else int32_t status = 0; - Assert(waitpid(proc->handle, &status, 0) == proc->handle); + cb_assert(waitpid(proc->handle, &status, 0) == proc->handle); if (WIFEXITED(status)) { proc->status_code = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { @@ -636,7 +648,7 @@ internal CB_Process _cb_cmd_run(CB_Cmd *cmd, struct Cb_Cmd_RunArgs args) { } internal void _cb_rebuild(int argc, char **argv, char *builder_src, ...) { - Assert(argc >= 1); + cb_assert(argc >= 1); char *exe_name = argv[0]; struct CB_PathList sources = {}; diff --git a/extra/tests.h b/extra/tests.h new file mode 100644 index 0000000..d1cc27c --- /dev/null +++ b/extra/tests.h @@ -0,0 +1,86 @@ +#ifndef TESTS_H +#define TESTS_H + +#include + +typedef void cb_test_func(void); + +struct CB_Test { + const char *name; + cb_test_func *function; +}; + +#if COMPILER_CL +#pragma section(".CRT$XCU", read) +typedef void cb_w32_test_func_init(void); +#define CB_TEST(FUNC_NAME) \ + static void FUNC_NAME(void); \ + internal void register_##FUNC_NAME(void) { \ + cb_test_register((struct CB_Test) { \ + .function = &FUNC_NAME, \ + .name = #FUNC_NAME, \ + }); \ + } \ + __declspec(allocate(".CRT$XCU")) \ + cb_w32_test_func_init *FUNC_NAME##_reg = register_##FUNC_NAME; \ + static void FUNC_NAME(void) +#else +#define CB_TEST(FUNC_NAME) \ + static void FUNC_NAME(void); \ + __attribute__((constructor)) \ + internal void register_##FUNC_NAME(void) { \ + cb_test_register((struct CB_Test) { \ + .function = &FUNC_NAME, \ + .name = #FUNC_NAME, \ + }); \ + } \ + static void FUNC_NAME(void) +#endif + +static void cb_test_run(void); + +internal void cb_test_register(struct CB_Test test); +internal void cb_assertion_test(const char *condition, + const char *file, + int32_t line); + + +// ====================================================================== +// Implementations +internal jmp_buf test_runner_jmpbuf = {0}; + +internal struct { + struct CB_Test *tests; + size_t count; + size_t capacity; +} cb_tests = {0}; + +static void cb_test_run(void) { + int32_t test_passed_count = 0; + cb_assertion_handler = cb_assertion_test; + for (size_t i = 0; i < cb_tests.count; ++i) { + printf("test %s ... ", cb_tests.tests[i].name); + if (setjmp(test_runner_jmpbuf) == 0) { + cb_tests.tests[i].function(); + printf(ANSI_COLOR_GREEN "ok\n" ANSI_COLOR_RESET); + test_passed_count += 1; + } + } + cb_assertion_handler = cb_assertion_break; + cb_println(CB_LogLevel_Info, "Summary: %d/%d tests passed", + test_passed_count, cb_tests.count); +} + +internal void cb_test_register(struct CB_Test test) { + cb_dyn_push_custom(&cb_tests, test, + tests, count, capacity); +} + +internal void cb_assertion_test(const char *condition, + const char *file, int32_t line) { + printf(ANSI_COLOR_RED "FAILED" ANSI_COLOR_RESET + ": `%s` (%s:%d)\n", condition, file, line); + longjmp(test_runner_jmpbuf, 1); +} + +#endif