// testLoad.c -- calogContextLoad across all four engines. // // Links every engine (built with all CALOG_WITH_* flags, set by the Makefile), so // calogRegisterBuiltinEngines auto-registers Lua, JS, Squirrel, and my-basic, and each // language is loaded by file extension. Also the first exercise of my-basic under the // actor/context-thread model. Verifies: each extension loads and runs its script; the // first registered engine wins when several files share a base name; a base that names // no file returns NULL. #define _POSIX_C_SOURCE 200809L #include "calog.h" #include #include #include #include // This test loads a .scm script, so it spins up an s7 interpreter, which keeps a small, // bounded set of interned "permanent" strings that s7_free intentionally never reclaims // (an s7 design characteristic, not a calog defect). Suppress exactly that allocation // site so the leak check stays meaningful. LSan calls this weak hook automatically. const char *__lsan_default_suppressions(void); const char *__lsan_default_suppressions(void) { return "leak:make_permanent_string\n"; } #define CHECK(cond, msg) checkImpl((cond), (msg), __FILE__, __LINE__) #define PUMP_LIMIT 4000 // ~2s at 0.5ms/iter static CalogT *calog = NULL; static _Atomic int64_t lastHit = 0; static int32_t testsRun = 0; static int32_t testsFailed = 0; static void checkImpl(bool condition, const char *message, const char *file, int32_t line); static int32_t hit(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData); static int64_t loadAndRun(const char *base); static void writeScript(const char *path, const char *content); static void checkImpl(bool condition, const char *message, const char *file, int32_t line) { testsRun++; if (!condition) { testsFailed++; printf("FAIL %s:%d %s\n", file, line, message); } } static int32_t hit(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) { (void)userData; calogValueNil(result); if (argCount >= 1 && args[0].type == calogIntE) { atomic_store(&lastHit, args[0].as.i); } return calogOkE; } static void writeScript(const char *path, const char *content) { FILE *file; file = fopen(path, "wb"); if (file != NULL) { fputs(content, file); fclose(file); } } // Load the script for base, pump until its hit() lands (or timeout), close, and return // the reported value -- 0 if it never ran, -1 if no file matched at all. static int64_t loadAndRun(const char *base) { CalogContextT *context; struct timespec ts = { 0, 500000 }; int32_t i; atomic_store(&lastHit, 0); context = calogContextLoad(calog, base); if (context == NULL) { return -1; } for (i = 0; i < PUMP_LIMIT && atomic_load(&lastHit) == 0; i++) { calogPump(calog); nanosleep(&ts, NULL); } calogContextClose(context); return atomic_load(&lastHit); } int main(void) { calog = calogCreate(); if (calog == NULL) { printf("calog create failed\n"); return 1; } calogRegister(calog, "hit", hit, NULL); calogRegisterBuiltinEngines(calog); // every engine the build linked (all seven) writeScript("clTest.lua", "hit(11)"); CHECK(loadAndRun("clTest") == 11, "loaded and ran a .lua script by base name"); remove("clTest.lua"); writeScript("clTest.js", "hit(12)"); CHECK(loadAndRun("clTest") == 12, "loaded and ran a .js script by base name"); remove("clTest.js"); writeScript("clTest.nut", "hit(13)"); CHECK(loadAndRun("clTest") == 13, "loaded and ran a .nut Squirrel script by base name"); remove("clTest.nut"); writeScript("clTest.bas", "hit(14)"); CHECK(loadAndRun("clTest") == 14, "loaded and ran a .bas my-basic script by base name"); remove("clTest.bas"); writeScript("clTest.scm", "(hit 15)"); CHECK(loadAndRun("clTest") == 15, "loaded and ran a .scm Scheme script by base name"); remove("clTest.scm"); writeScript("clTest.wren", "Calog.call(\"hit\", [16])"); CHECK(loadAndRun("clTest") == 16, "loaded and ran a .wren script by base name"); remove("clTest.wren"); writeScript("clTest.be", "hit(17)"); CHECK(loadAndRun("clTest") == 17, "loaded and ran a .be Berry script by base name"); remove("clTest.be"); // First match wins: Lua is registered before my-basic, so .lua beats .bas. writeScript("clPrio.lua", "hit(21)"); writeScript("clPrio.bas", "hit(22)"); CHECK(loadAndRun("clPrio") == 21, "first registered engine wins when several files share a base"); remove("clPrio.lua"); remove("clPrio.bas"); // No file with any registered extension exists -> NULL. CHECK(calogContextLoad(calog, "clNoSuchBase") == NULL, "calogContextLoad returns NULL when nothing matches"); calogDestroy(calog); printf("\n%d checks, %d failed\n", testsRun, testsFailed); fflush(stdout); if (testsFailed != 0) { return 1; } return 0; }