calog/tests/testPolyglot.c

168 lines
5.2 KiB
C

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