]> git.leonardobizzoni.com Git - CBuild/commitdiff
Testing functionality
authorLeonardoBizzoni <leo2002714@gmail.com>
Mon, 13 Oct 2025 10:15:44 +0000 (12:15 +0200)
committerLeonardoBizzoni <leo2002714@gmail.com>
Mon, 13 Oct 2025 10:15:44 +0000 (12:15 +0200)
cbuild.h
extra/tests.h [new file with mode: 0644]

index 8538f96bf234556eaf2e060b9f85bf5912c9257e..13d06729e7dd509c81854578cbf15511ce9177e7 100644 (file)
--- a/cbuild.h
+++ b/cbuild.h
@@ -56,6 +56,7 @@
 #endif
 
 #if !CPP
+#  define BOOL_DEFINED 1
 #  if __STDC_VERSION__ >= 199901L
 #    include <stdbool.h>
 #  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 (file)
index 0000000..d1cc27c
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef TESTS_H
+#define TESTS_H
+
+#include <setjmp.h>
+
+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