calog/tests/testLoad.c

140 lines
4.5 KiB
C

// 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 <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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;
}