Files
deusdata--codebase-memory-mcp/tests/test_helpers.h
T
wehub-resource-sync 41cb1c0170
OpenSSF Scorecard / scorecard (push) Failing after 0s
DCO / dco (push) Failing after 0s
CodeQL SAST / analyze (push) Failing after 1s
Deploy Pages / deploy (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:28:05 +08:00

172 lines
5.1 KiB
C

/*
* test_helpers.h — Cross-platform test fixture helpers.
*
* Replaces system("rm -rf"), system("mkdir -p && echo >"), chmod(),
* and hardcoded /tmp/ paths with portable C implementations.
* Uses compat.h/compat_fs.h underneath — same abstraction layer
* as production code.
*
* All functions are static inline to avoid linker issues when
* included from multiple test files.
*/
#ifndef TEST_HELPERS_H
#define TEST_HELPERS_H
#include "../src/foundation/compat.h"
#include "../src/foundation/compat_fs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
/* ── Path building ────────────────────────────────────────────── */
/* Build a path from base + relative. Uses a static buffer — not reentrant.
* Usage: th_write_file(TH_PATH(base, "src/main.go"), "content"); */
#define TH_PATH(base, rel) th_path_join(base, rel)
static inline const char *th_path_join(const char *base, const char *rel) {
static char buf[4][1024];
static int idx = 0;
int i = idx;
idx = (idx + 1) & 3;
snprintf(buf[i], sizeof(buf[i]), "%s/%s", base, rel);
return buf[i];
}
/* ── File writing ─────────────────────────────────────────────── */
/* Write content to a file, creating parent directories as needed. */
static inline int th_write_file(const char *path, const char *content) {
/* Create parent directories */
char dir[1024];
snprintf(dir, sizeof(dir), "%s", path);
char *last_slash = strrchr(dir, '/');
#ifdef _WIN32
char *last_bslash = strrchr(dir, '\\');
if (last_bslash && (!last_slash || last_bslash > last_slash)) {
last_slash = last_bslash;
}
#endif
if (last_slash) {
*last_slash = '\0';
cbm_mkdir_p(dir, 0755);
}
FILE *f = fopen(path, "w");
if (!f) {
return -1;
}
if (content && content[0]) {
fputs(content, f);
}
fclose(f);
return 0;
}
/* Append content to a file. */
static inline int th_append_file(const char *path, const char *content) {
FILE *f = fopen(path, "a");
if (!f) {
return -1;
}
if (content && content[0]) {
fputs(content, f);
}
fclose(f);
return 0;
}
/* ── Directory creation ───────────────────────────────────────── */
/* Create a directory and all parents. Returns 0 on success. */
static inline int th_mkdir_p(const char *path) {
return cbm_mkdir_p(path, 0755) ? 0 : -1;
}
/* ── Recursive directory removal ──────────────────────────────── */
/* Remove a file or directory tree recursively. Cross-platform rm -rf. */
static inline int th_rmtree(const char *path) {
struct stat st;
if (stat(path, &st) != 0) {
return 0; /* doesn't exist — success */
}
if (!S_ISDIR(st.st_mode)) {
return cbm_unlink(path);
}
/* Directory — recurse into children */
cbm_dir_t *d = cbm_opendir(path);
if (!d) {
return -1;
}
cbm_dirent_t *entry;
int rc = 0;
while ((entry = cbm_readdir(d)) != NULL) {
if (strcmp(entry->name, ".") == 0 || strcmp(entry->name, "..") == 0) {
continue;
}
char child[1024];
snprintf(child, sizeof(child), "%s/%s", path, entry->name);
if (entry->is_dir) {
if (th_rmtree(child) != 0) {
rc = -1;
}
} else {
if (cbm_unlink(child) != 0) {
rc = -1;
}
}
}
cbm_closedir(d);
cbm_rmdir(path);
return rc;
}
/* ── Temp directory creation ──────────────────────────────────── */
/* Create a temporary directory. Returns static buffer with path.
* Pattern: prefix is used as part of the dirname. */
static inline char *th_mktempdir(const char *prefix) {
static char buf[256];
#ifdef _WIN32
const char *tmp = getenv("TEMP");
if (!tmp) tmp = getenv("TMP");
if (!tmp) tmp = "C:\\Temp";
snprintf(buf, sizeof(buf), "%s\\%s_XXXXXX", tmp, prefix);
#else
snprintf(buf, sizeof(buf), "/tmp/%s_XXXXXX", prefix);
#endif
if (!cbm_mkdtemp(buf)) {
return NULL;
}
return buf;
}
/* ── File permissions (no-op on Windows) ──────────────────────── */
/* Make a file executable. On Windows this is a no-op (all files are
* "executable" if they have the right extension). */
static inline void th_make_executable(const char *path) {
#ifndef _WIN32
chmod(path, 0755);
#else
(void)path;
#endif
}
/* ── Cleanup helper ───────────────────────────────────────────── */
/* Remove a temp directory tree. Safe to call with NULL. */
static inline void th_cleanup(const char *path) {
if (path && path[0]) {
th_rmtree(path);
}
}
#endif /* TEST_HELPERS_H */