// testPolyglot.c -- integration test: one broker, two engines. // // Demonstrates the whole point of the broker: a single C native registered once // is callable from both Lua and my-basic, and a function written in Lua is // callable from a my-basic program -- routed entirely through the broker, with // neither engine aware the other exists. #include "calogInternal.h" #include "luaAdapter.h" #include "mybasicAdapter.h" #include #include #include #define CHECK(cond, msg) checkImpl((cond), (msg), __FILE__, __LINE__) #define LUA_CTX_ID 1 #define BASIC_CTX_ID 2 static CalogT *broker = NULL; static CalogLuaT *lua = NULL; static CalogMyBasicT *basic = NULL; static CalogFnT *luaCallable = NULL; static CalogValueT recorded; static int32_t testsRun = 0; static int32_t testsFailed = 0; static int32_t basicRun(const char *source); static int32_t callableTrampoline(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData); static void checkImpl(bool condition, const char *message, const char *file, int32_t line); static int32_t nativeAdd(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData); static int32_t nativeRecord(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData); static void testBasicCallsLua(void); static void testSharedNative(void); static int32_t basicRun(const char *source) { int32_t status; if (basic != NULL) { calogMyBasicDestroy(basic); basic = NULL; } status = calogMyBasicCreate(&basic, broker, BASIC_CTX_ID); if (status != calogOkE) { return status; } calogMyBasicExpose(basic, "add"); calogMyBasicExpose(basic, "record"); calogMyBasicExpose(basic, "luaDouble"); return calogMyBasicRun(basic, source); } static int32_t callableTrampoline(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) { return calogFnInvoke((CalogFnT *)userData, args, argCount, result); } 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 nativeAdd(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) { (void)userData; if (argCount != 2 || args[0].type != calogIntE || args[1].type != calogIntE) { return calogFail(result, calogErrArgE, "add expects two integers"); } calogValueInt(result, args[0].as.i + args[1].as.i); return calogOkE; } static int32_t nativeRecord(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) { int32_t status; (void)userData; calogValueNil(result); calogValueFree(&recorded); if (argCount < 1) { return calogOkE; } status = calogValueCopy(&recorded, &args[0]); if (status != calogOkE) { return calogFail(result, status, "record copy failed"); } return calogOkE; } static void testBasicCallsLua(void) { int32_t status; // luaDouble is implemented in Lua; my-basic calls it by name through the // broker with no knowledge that another language is involved. status = basicRun("record(luadouble(21))"); CHECK(status == calogOkE, "BASIC calling a Lua function run"); CHECK(recorded.type == calogIntE && recorded.as.i == 42, "BASIC invoked the Lua function via the broker"); } static void testSharedNative(void) { int32_t status; status = calogLuaRun(lua, "record(add(2, 3))"); CHECK(status == calogOkE, "shared native from Lua run"); CHECK(recorded.type == calogIntE && recorded.as.i == 5, "one C native called from Lua"); status = basicRun("record(add(10, 20))"); CHECK(status == calogOkE, "shared native from BASIC run"); CHECK(recorded.type == calogIntE && recorded.as.i == 30, "the same C native called from BASIC"); } int main(void) { int32_t status; calogValueNil(&recorded); broker = calogBrokerCreate(); if (broker == NULL) { printf("broker create failed\n"); return 1; } calogRegister(broker, "add", nativeAdd, NULL); calogRegister(broker, "record", nativeRecord, NULL); status = calogLuaCreate(&lua, broker, LUA_CTX_ID); if (status != calogOkE) { printf("lua context create failed\n"); return 1; } calogLuaExpose(lua, "add"); calogLuaExpose(lua, "record"); // Define a function in Lua, export it, and register it as a broker native so // any other language can call it. calogLuaRun(lua, "function luaDouble(x) return x * 2 end"); status = calogLuaExport(lua, "luaDouble", &luaCallable); if (status != calogOkE) { printf("lua export failed\n"); return 1; } calogRegister(broker, "luaDouble", callableTrampoline, luaCallable); testSharedNative(); testBasicCallsLua(); calogValueFree(&recorded); if (basic != NULL) { calogMyBasicDestroy(basic); } calogFnRelease(luaCallable); calogLuaDestroy(lua); calogBrokerDestroy(broker); printf("\n%d checks, %d failed\n", testsRun, testsFailed); fflush(stdout); if (testsFailed != 0) { return 1; } return 0; }