238 lines
7.7 KiB
C
238 lines
7.7 KiB
C
// testLua.c -- tests for the Lua 5.4 adapter against the broker core.
|
|
//
|
|
// Exercises: a broker native called from Lua, scalar/table marshalling in both
|
|
// directions (binary-safe strings included), a Lua function exported and invoked
|
|
// from C, and a function value pushed into Lua and called there.
|
|
|
|
#include "calogInternal.h"
|
|
#include "luaAdapter.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define CHECK(cond, msg) checkImpl((cond), (msg), __FILE__, __LINE__)
|
|
|
|
#define LIST_ELEM_BASE 10
|
|
#define LIST_ELEMS 3
|
|
|
|
static CalogT *broker = NULL;
|
|
static CalogLuaT *lua = NULL;
|
|
static CalogValueT recorded;
|
|
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 nativeAdd(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
|
|
static int32_t nativeGetAdder(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
|
|
static int32_t nativeMakeList(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
|
|
static int32_t nativeRecord(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
|
|
static void testBinaryString(void);
|
|
static void testExportInvoke(void);
|
|
static void testFunctionValueIntoLua(void);
|
|
static void testNativeFromLua(void);
|
|
static void testTableFromNative(void);
|
|
static void testTableToNative(void);
|
|
|
|
|
|
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 nativeGetAdder(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
|
|
CalogFnT *callable;
|
|
int32_t status;
|
|
|
|
(void)args;
|
|
(void)argCount;
|
|
(void)userData;
|
|
status = calogFnCreate(&callable, broker, nativeAdd, NULL, NULL, 0);
|
|
if (status != calogOkE) {
|
|
return calogFail(result, status, "getAdder out of memory");
|
|
}
|
|
calogValueFn(result, callable);
|
|
return calogOkE;
|
|
}
|
|
|
|
|
|
static int32_t nativeMakeList(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
|
|
CalogAggT *aggregate;
|
|
CalogValueT element;
|
|
int32_t status;
|
|
int32_t index;
|
|
|
|
(void)args;
|
|
(void)argCount;
|
|
(void)userData;
|
|
status = calogAggCreate(&aggregate, calogListE);
|
|
if (status != calogOkE) {
|
|
return calogFail(result, status, "makeList out of memory");
|
|
}
|
|
for (index = 0; index < LIST_ELEMS; index++) {
|
|
calogValueInt(&element, (int64_t)(index + 1) * LIST_ELEM_BASE);
|
|
status = calogAggPush(aggregate, &element);
|
|
if (status != calogOkE) {
|
|
calogValueFree(&element);
|
|
calogAggFree(aggregate);
|
|
return calogFail(result, status, "makeList push failed");
|
|
}
|
|
}
|
|
calogValueAgg(result, aggregate);
|
|
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 testBinaryString(void) {
|
|
int32_t status;
|
|
|
|
status = calogLuaRun(lua, "record('a\\0b')");
|
|
CHECK(status == calogOkE, "lua binary string run");
|
|
CHECK(recorded.type == calogStringE && recorded.as.s.length == 3, "binary string length preserved");
|
|
CHECK(recorded.as.s.bytes[0] == 'a' && recorded.as.s.bytes[1] == '\0' && recorded.as.s.bytes[2] == 'b', "embedded NUL survived marshalling");
|
|
}
|
|
|
|
|
|
static void testExportInvoke(void) {
|
|
CalogFnT *doubler;
|
|
CalogValueT arg;
|
|
CalogValueT result;
|
|
int32_t status;
|
|
|
|
status = calogLuaRun(lua, "function doubler(x) return x * 2 end");
|
|
CHECK(status == calogOkE, "define doubler");
|
|
status = calogLuaExport(lua, "doubler", &doubler);
|
|
CHECK(status == calogOkE, "export doubler");
|
|
|
|
calogValueInt(&arg, 21);
|
|
status = calogFnInvoke(doubler, &arg, 1, &result);
|
|
CHECK(status == calogOkE, "invoke exported Lua function from C");
|
|
CHECK(result.type == calogIntE && result.as.i == 42, "exported Lua function result");
|
|
calogValueFree(&result);
|
|
calogValueFree(&arg);
|
|
calogFnRelease(doubler);
|
|
}
|
|
|
|
|
|
static void testFunctionValueIntoLua(void) {
|
|
int32_t status;
|
|
|
|
status = calogLuaRun(lua, "record(getAdder()(2, 3))");
|
|
CHECK(status == calogOkE, "function value into Lua run");
|
|
CHECK(recorded.type == calogIntE && recorded.as.i == 5, "function value called inside Lua");
|
|
}
|
|
|
|
|
|
static void testNativeFromLua(void) {
|
|
int32_t status;
|
|
|
|
status = calogLuaRun(lua, "record(add(3, 4))");
|
|
CHECK(status == calogOkE, "native from Lua run");
|
|
CHECK(recorded.type == calogIntE && recorded.as.i == 7, "native add result recorded");
|
|
}
|
|
|
|
|
|
static void testTableFromNative(void) {
|
|
int32_t status;
|
|
|
|
status = calogLuaRun(lua, "local t = makeList(); record(t[1] + t[2] + t[3])");
|
|
CHECK(status == calogOkE, "table from native run");
|
|
CHECK(recorded.type == calogIntE && recorded.as.i == 60, "aggregate marshalled to Lua table (values)");
|
|
|
|
status = calogLuaRun(lua, "record(#makeList())");
|
|
CHECK(status == calogOkE, "table length run");
|
|
CHECK(recorded.type == calogIntE && recorded.as.i == LIST_ELEMS, "aggregate marshalled to Lua table (length)");
|
|
}
|
|
|
|
|
|
static void testTableToNative(void) {
|
|
CalogValueT key;
|
|
CalogValueT *found;
|
|
int32_t status;
|
|
|
|
status = calogLuaRun(lua, "record({10, 20, x = true})");
|
|
CHECK(status == calogOkE, "table to native run");
|
|
CHECK(recorded.type == calogAggE, "Lua table marshalled to aggregate");
|
|
CHECK(recorded.as.agg->arrayCount == 2, "table array part count");
|
|
CHECK(recorded.as.agg->array[0].as.i == 10 && recorded.as.agg->array[1].as.i == 20, "table array part values");
|
|
CHECK(recorded.as.agg->pairCount == 1, "table hash part count");
|
|
|
|
calogValueString(&key, "x", 1);
|
|
found = calogAggGet(recorded.as.agg, &key);
|
|
calogValueFree(&key);
|
|
CHECK(found != NULL && found->type == calogBoolE && found->as.b == true, "table hash part value");
|
|
}
|
|
|
|
|
|
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);
|
|
calogRegister(broker, "makeList", nativeMakeList, NULL);
|
|
calogRegister(broker, "getAdder", nativeGetAdder, NULL);
|
|
|
|
status = calogLuaCreate(&lua, broker, 1);
|
|
if (status != calogOkE) {
|
|
printf("lua context create failed\n");
|
|
return 1;
|
|
}
|
|
calogLuaExpose(lua, "add");
|
|
calogLuaExpose(lua, "record");
|
|
calogLuaExpose(lua, "makeList");
|
|
calogLuaExpose(lua, "getAdder");
|
|
|
|
testNativeFromLua();
|
|
testTableToNative();
|
|
testTableFromNative();
|
|
testExportInvoke();
|
|
testFunctionValueIntoLua();
|
|
testBinaryString();
|
|
|
|
calogValueFree(&recorded);
|
|
calogLuaDestroy(lua);
|
|
calogBrokerDestroy(broker);
|
|
|
|
printf("\n%d checks, %d failed\n", testsRun, testsFailed);
|
|
if (testsFailed != 0) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|