9dd925a87d
CI / lint (pull_request) Successful in 9s
CI / sanitizers (address) (pull_request) Successful in 15s
CI / sanitizers (undefined) (pull_request) Successful in 15s
CI / coverage (pull_request) Successful in 11s
CI / fuzz-build (pull_request) Successful in 13s
CI / valgrind (pull_request) Successful in 12s
CI / build-and-test (pull_request) Successful in 54s
116 lines
7.9 KiB
C
116 lines
7.9 KiB
C
#ifndef TEST_UTILS_H
|
|
#define TEST_UTILS_H
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
|
|
// Detect if running under valgrind by checking /proc/self/maps for vgpreload.
|
|
// This is used to skip fork-based tests that are incompatible with valgrind
|
|
// (the instrumented parent runs too slowly, causing pipe timeouts).
|
|
static inline bool is_running_under_valgrind(void) {
|
|
FILE* f = fopen("/proc/self/maps", "r");
|
|
if (!f)
|
|
return false;
|
|
char buf[4096];
|
|
size_t n = fread(buf, 1, sizeof(buf) - 1, f);
|
|
fclose(f);
|
|
buf[n] = '\0';
|
|
return strstr(buf, "vgpreload") != NULL;
|
|
}
|
|
|
|
// Global test suite status
|
|
extern int tests_run;
|
|
extern int tests_failed;
|
|
extern bool current_test_failed;
|
|
|
|
// Helper to run a test function
|
|
#define RUN_TEST(test_func) \
|
|
do { \
|
|
printf("Running %s...\n", #test_func); \
|
|
tests_run++; \
|
|
current_test_failed = false; \
|
|
test_func(); \
|
|
if (current_test_failed) { \
|
|
tests_failed++; \
|
|
printf(" \033[1;31m[FAILED]\033[0m %s\n", #test_func); \
|
|
} else { \
|
|
printf(" \033[1;32m[PASSED]\033[0m %s\n", #test_func); \
|
|
} \
|
|
} while (0)
|
|
|
|
// Assertion macros
|
|
#define EXPECT_TRUE(condition) \
|
|
do { \
|
|
if (!(condition)) { \
|
|
printf(" \033[1;31m[FAIL]\033[0m %s:%d: Assertion failed: %s is false\n", __FILE__, \
|
|
__LINE__, #condition); \
|
|
current_test_failed = true; \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_FALSE(condition) \
|
|
do { \
|
|
if (condition) { \
|
|
printf(" \033[1;31m[FAIL]\033[0m %s:%d: Assertion failed: %s is true\n", __FILE__, \
|
|
__LINE__, #condition); \
|
|
current_test_failed = true; \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_EQ_INT(actual, expected) \
|
|
do { \
|
|
int act = (actual); \
|
|
int exp = (expected); \
|
|
if (act != exp) { \
|
|
printf(" \033[1;31m[FAIL]\033[0m %s:%d: Expected %d, got %d\n", __FILE__, __LINE__, exp, \
|
|
act); \
|
|
current_test_failed = true; \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_EQ_STR(actual, expected) \
|
|
do { \
|
|
const char* act = (actual); \
|
|
const char* exp = (expected); \
|
|
if (act == NULL || exp == NULL) { \
|
|
if (act != exp) { \
|
|
printf(" \033[1;31m[FAIL]\033[0m %s:%d: Expected %s, got %s\n", __FILE__, __LINE__, \
|
|
exp ? exp : "NULL", act ? act : "NULL"); \
|
|
current_test_failed = true; \
|
|
return; \
|
|
} \
|
|
} else if (strcmp(act, exp) != 0) { \
|
|
printf(" \033[1;31m[FAIL]\033[0m %s:%d: Expected \"%s\", got \"%s\"\n", __FILE__, \
|
|
__LINE__, exp, act); \
|
|
current_test_failed = true; \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_NOT_NULL(ptr) \
|
|
do { \
|
|
if ((ptr) == NULL) { \
|
|
printf(" \033[1;31m[FAIL]\033[0m %s:%d: Expected non-null pointer, got NULL\n", __FILE__, \
|
|
__LINE__); \
|
|
current_test_failed = true; \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define EXPECT_NULL(ptr) \
|
|
do { \
|
|
if ((ptr) != NULL) { \
|
|
printf(" \033[1;31m[FAIL]\033[0m %s:%d: Expected NULL, got %p\n", __FILE__, __LINE__, \
|
|
(void*)(ptr)); \
|
|
current_test_failed = true; \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#endif
|