aboutsummaryrefslogtreecommitdiff
path: root/test/lapi.test.js
diff options
context:
space:
mode:
Diffstat (limited to 'test/lapi.test.js')
-rw-r--r--test/lapi.test.js382
1 files changed, 382 insertions, 0 deletions
diff --git a/test/lapi.test.js b/test/lapi.test.js
new file mode 100644
index 0000000..f6bafc3
--- /dev/null
+++ b/test/lapi.test.js
@@ -0,0 +1,382 @@
+"use strict";
+
+const {toByteCode} = require("./tests.js");
+
+const lua = require('../src/lua.js');
+const lauxlib = require("../src/lauxlib.js");
+const {to_luastring} = require("../src/fengaricore.js");
+
+
+test('luaL_newstate, lua_pushnil, luaL_typename', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_pushnil(L);
+ }
+
+ expect(lauxlib.luaL_typename(L, -1))
+ .toEqual(to_luastring("nil"));
+});
+
+
+test('lua_pushnumber', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_pushnumber(L, 10.5);
+ }
+
+ expect(lauxlib.luaL_typename(L, -1))
+ .toEqual(to_luastring("number"));
+
+ expect(lua.lua_tonumber(L, -1))
+ .toBe(10.5);
+});
+
+
+test('lua_pushinteger', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_pushinteger(L, 10);
+ }
+
+ expect(lauxlib.luaL_typename(L, -1))
+ .toEqual(to_luastring("number"));
+
+ expect(lua.lua_tointeger(L, -1))
+ .toBe(10);
+});
+
+
+test('lua_pushliteral', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_pushliteral(L, "hello");
+ }
+
+ expect(lauxlib.luaL_typename(L, -1))
+ .toEqual(to_luastring("string"));
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("hello");
+});
+
+
+test('lua_pushboolean', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_pushboolean(L, true);
+ }
+
+ expect(lauxlib.luaL_typename(L, -1))
+ .toEqual(to_luastring("boolean"));
+
+ expect(lua.lua_toboolean(L, -1))
+ .toBe(true);
+});
+
+
+test('lua_pushvalue', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_pushliteral(L, "hello");
+ lua.lua_pushvalue(L, -1);
+ }
+
+ expect(lauxlib.luaL_typename(L, -1))
+ .toEqual(to_luastring("string"));
+
+ expect(lauxlib.luaL_typename(L, -2))
+ .toEqual(to_luastring("string"));
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("hello");
+
+ expect(lua.lua_tojsstring(L, -2))
+ .toBe("hello");
+});
+
+
+test('lua_pushjsclosure', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ let fn = function(L) {
+ return 0;
+ };
+ lua.lua_pushliteral(L, "a value associated to the C closure");
+ lua.lua_pushjsclosure(L, fn, 1);
+ }
+
+ expect(lauxlib.luaL_typename(L, -1))
+ .toEqual(to_luastring("function"));
+});
+
+
+test('lua_pushjsfunction', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ let fn = function(L) {
+ return 0;
+ };
+ lua.lua_pushjsfunction(L, fn);
+ }
+
+ expect(lauxlib.luaL_typename(L, -1))
+ .toEqual(to_luastring("function"));
+});
+
+
+test('lua_call (calling a light JS function)', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ let fn = function(L) {
+ lua.lua_pushliteral(L, "hello");
+ return 1;
+ };
+ lua.lua_pushjsfunction(L, fn);
+ lua.lua_call(L, 0, 1);
+ }
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("hello");
+});
+
+
+test('lua_call (calling a JS closure)', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ let fn = function(L) {
+ lua.lua_pushstring(L, lua.lua_tostring(L, lua.lua_upvalueindex(1)));
+ return 1;
+ };
+ lua.lua_pushliteral(L, "upvalue hello!");
+ lua.lua_pushjsclosure(L, fn, 1);
+ lua.lua_call(L, 0, 1);
+ }
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("upvalue hello!");
+});
+
+
+test('lua_pcall (calling a light JS function)', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ let fn = function(L) {
+ lua.lua_pushliteral(L, "hello");
+ return 1;
+ };
+ lua.lua_pushjsfunction(L, fn);
+ expect(lua.lua_pcall(L, 0, 1, 0)).toBe(lua.LUA_OK);
+ }
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("hello");
+});
+
+
+test('lua_pcall that breaks', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ let fn = function(L) {
+ return "undefined_value";
+ };
+ lua.lua_pushjsfunction(L, fn);
+ expect(lua.lua_pcall(L, 0, 1, 0)).not.toBe(lua.LUA_OK);
+ }
+});
+
+
+test('lua_pop', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_pushliteral(L, "hello");
+ lua.lua_pushliteral(L, "world");
+ lua.lua_pop(L, 1);
+ }
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("hello");
+});
+
+
+test('lua_load with no chunkname', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_load(L, function(L, s) {
+ let r = s.code;
+ s.code = null;
+ return r;
+ }, {
+ code: to_luastring("return 'hello'")
+ }, null, null);
+ lua.lua_call(L, 0, 1);
+ }
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("hello");
+});
+
+test('lua_load and lua_call it', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ let luaCode = `
+ local a = "JS > Lua > JS \\\\o/"
+ return a
+ `;
+ let bc = toByteCode(luaCode);
+ lua.lua_load(L, function(L, s) {
+ let r = s.bc;
+ s.bc = null;
+ return r;
+ }, {bc: bc}, to_luastring("test-lua_load"), to_luastring("binary"));
+ lua.lua_call(L, 0, 1);
+ }
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("JS > Lua > JS \\o/");
+});
+
+
+test('lua script reads js upvalues', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ let luaCode = `
+ return js .. " world"
+ `;
+ expect(lauxlib.luaL_loadstring(L, to_luastring(luaCode))).toBe(lua.LUA_OK);
+ lua.lua_pushliteral(L, "hello");
+ lua.lua_setglobal(L, to_luastring("js"));
+ lua.lua_call(L, 0, 1);
+ }
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("hello world");
+});
+
+
+test('lua_createtable', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_createtable(L, 3, 3);
+ }
+
+ expect(lua.lua_istable(L, -1)).toBe(true);
+});
+
+
+test('lua_newtable', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_newtable(L);
+ }
+
+ expect(lua.lua_istable(L, -1)).toBe(true);
+});
+
+
+test('lua_settable, lua_gettable', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ {
+ lua.lua_newtable(L);
+
+ lua.lua_pushliteral(L, "key");
+ lua.lua_pushliteral(L, "value");
+
+ lua.lua_settable(L, -3);
+
+ lua.lua_pushliteral(L, "key");
+ lua.lua_gettable(L, -2);
+ }
+
+ expect(lua.lua_tojsstring(L, -1))
+ .toBe("value");
+});
+
+describe('lua_atnativeerror', () => {
+ test('no native error handler', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ let errob = {};
+
+ lua.lua_pushcfunction(L, function(L) {
+ throw errob;
+ });
+ // without a native error handler pcall should be -1
+ expect(lua.lua_pcall(L, 0, 0, 0)).toBe(-1);
+ });
+
+ test('native error handler returns string', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ let errob = {};
+
+ lua.lua_atnativeerror(L, function(L) {
+ let e = lua.lua_touserdata(L, 1);
+ expect(e).toBe(errob);
+ lua.lua_pushstring(L, to_luastring("runtime error!"));
+ return 1;
+ });
+ lua.lua_pushcfunction(L, function(L) {
+ throw errob;
+ });
+ expect(lua.lua_pcall(L, 0, 0, 0)).toBe(lua.LUA_ERRRUN);
+ expect(lua.lua_tojsstring(L, -1)).toBe("runtime error!");
+ });
+
+ test('native error handler rethrows lua error', () => {
+ let L = lauxlib.luaL_newstate();
+ if (!L) throw Error("failed to create lua state");
+
+ let errob = {};
+
+ lua.lua_atnativeerror(L, function(L) {
+ let e = lua.lua_touserdata(L, 1);
+ expect(e).toBe(errob);
+ lauxlib.luaL_error(L, to_luastring("runtime error!"));
+ });
+ lua.lua_pushcfunction(L, function(L) {
+ throw errob;
+ });
+ expect(lua.lua_pcall(L, 0, 0, 0)).toBe(lua.LUA_ERRRUN);
+ expect(lua.lua_tojsstring(L, -1)).toBe("runtime error!");
+ });
+});