"use strict"; const test = require('tape'); const tests = require("./tests.js"); const toByteCode = tests.toByteCode; 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', function (t) { let L; t.plan(2); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lua.lua_pushnil(L); }, "JS Lua program ran without error"); t.deepEqual( lauxlib.luaL_typename(L, -1), "nil".split('').map(e => e.charCodeAt(0)), "Correct element(s) on the stack" ); }); test('lua_pushnumber', function (t) { let L; t.plan(3); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lua.lua_pushnumber(L, 10.5); }, "JS Lua program ran without error"); t.deepEqual( lauxlib.luaL_typename(L, -1), "number".split('').map(e => e.charCodeAt(0)), "Correct element(s) on the stack" ); t.strictEqual( lua.lua_tonumber(L, -1), 10.5, "top is correct" ); }); test('lua_pushinteger', function (t) { let L; t.plan(3); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lua.lua_pushinteger(L, 10); }, "JS Lua program ran without error"); t.deepEqual( lauxlib.luaL_typename(L, -1), "number".split('').map(e => e.charCodeAt(0)), "Correct element(s) on the stack" ); t.strictEqual( lua.lua_tointeger(L, -1), 10, "top is correct" ); }); test('lua_pushliteral', function (t) { let L; t.plan(3); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lua.lua_pushliteral(L, "hello"); }, "JS Lua program ran without error"); t.deepEqual( lauxlib.luaL_typename(L, -1), "string".split('').map(e => e.charCodeAt(0)), "Correct element(s) on the stack" ); t.strictEqual( lua.lua_tojsstring(L, -1), "hello", "top is correct" ); }); test('lua_pushboolean', function (t) { let L; t.plan(3); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lua.lua_pushboolean(L, true); }, "JS Lua program ran without error"); t.deepEqual( lauxlib.luaL_typename(L, -1), "boolean".split('').map(e => e.charCodeAt(0)), "Correct element(s) on the stack" ); t.strictEqual( lua.lua_toboolean(L, -1), true, "top is correct" ); }); test('lua_pushvalue', function (t) { let L; t.plan(5); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lua.lua_pushliteral(L, "hello"); lua.lua_pushvalue(L, -1); }, "JS Lua program ran without error"); t.deepEqual( lauxlib.luaL_typename(L, -1), "string".split('').map(e => e.charCodeAt(0)), "Correct element(s) on the stack" ); t.deepEqual( lauxlib.luaL_typename(L, -2), "string".split('').map(e => e.charCodeAt(0)), "Correct element(s) on the stack" ); t.strictEqual( lua.lua_tojsstring(L, -1), "hello", "Correct element(s) on the stack" ); t.strictEqual( lua.lua_tojsstring(L, -2), "hello", "Correct element(s) on the stack" ); }); test('lua_pushjsclosure', function (t) { let L; t.plan(2); t.doesNotThrow(function () { let fn = function(L) { return 0; }; L = lauxlib.luaL_newstate(); lua.lua_pushliteral(L, "a value associated to the C closure"); lua.lua_pushjsclosure(L, fn, 1); }, "JS Lua program ran without error"); t.deepEqual( lauxlib.luaL_typename(L, -1), "function".split('').map(e => e.charCodeAt(0)), "Correct element(s) on the stack" ); }); test('lua_pushjsfunction', function (t) { let L; t.plan(2); t.doesNotThrow(function () { let fn = function(L) { return 0; }; L = lauxlib.luaL_newstate(); lua.lua_pushjsfunction(L, fn); }, "JS Lua program ran without error"); t.deepEqual( lauxlib.luaL_typename(L, -1), "function".split('').map(e => e.charCodeAt(0)), "Correct element(s) on the stack" ); }); test('lua_call (calling a light JS function)', function (t) { let L; t.plan(2); t.doesNotThrow(function () { let fn = function(L) { lua.lua_pushliteral(L, "hello"); return 1; }; L = lauxlib.luaL_newstate(); lua.lua_pushjsfunction(L, fn); lua.lua_call(L, 0, 1); }, "JS Lua program ran without error"); t.strictEqual( lua.lua_tojsstring(L, -1), "hello", "top is correct" ); }); test('lua_call (calling a JS closure)', function (t) { let L; t.plan(2); t.doesNotThrow(function () { let fn = function(L) { lua.lua_pushstring(L, lua.lua_tostring(L, lua.lua_upvalueindex(1))); return 1; }; L = lauxlib.luaL_newstate(); lua.lua_pushliteral(L, "upvalue hello !"); lua.lua_pushjsclosure(L, fn, 1); lua.lua_call(L, 0, 1); }, "JS Lua program ran without error"); t.strictEqual( lua.lua_tojsstring(L, -1), "upvalue hello !", "top is correct" ); }); test('lua_pcall (calling a light JS function)', function (t) { let L; t.plan(2); t.doesNotThrow(function () { let fn = function(L) { lua.lua_pushliteral(L, "hello"); return 1; }; L = lauxlib.luaL_newstate(); lua.lua_pushjsfunction(L, fn); lua.lua_pcall(L, 0, 1, 0); }, "JS Lua program ran without error"); t.strictEqual( lua.lua_tojsstring(L, -1), "hello", "top is correct" ); }); test('lua_pcall that breaks', function (t) { let L; t.plan(1); t.doesNotThrow(function () { let fn = function(L) { return "undefined_value"; }; L = lauxlib.luaL_newstate(); lua.lua_pushjsfunction(L, fn); lua.lua_pcall(L, 0, 1, 0); }, "JS Lua program ran without error"); console.log(L.stack[L.top - 1].value); }); test('lua_pop', function (t) { let L; t.plan(2); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lua.lua_pushliteral(L, "hello"); lua.lua_pushliteral(L, "world"); lua.lua_pop(L, 1); }, "JS Lua program ran without error"); t.strictEqual( lua.lua_tojsstring(L, -1), "hello", "Correct element(s) on the stack" ); }); test('lua_load with no chunkname', function (t) { let L; t.plan(2); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); 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); }, "JS Lua program ran without error"); t.strictEqual( lua.lua_tojsstring(L, -1), "hello", "Correct element(s) on the stack" ); }); test('lua_load and lua_call it', function (t) { let luaCode = ` local a = "JS > Lua > JS \\\\o/" return a `, L; t.plan(2); t.doesNotThrow(function () { let bc = toByteCode(luaCode); L = lauxlib.luaL_newstate(); 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); }, "JS Lua program ran without error"); t.strictEqual( lua.lua_tojsstring(L, -1), "JS > Lua > JS \\o/", "Correct element(s) on the stack" ); }); test('lua script reads js upvalues', function (t) { let luaCode = ` return js .. " world" `, L; t.plan(2); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lauxlib.luaL_loadstring(L, to_luastring(luaCode)); lua.lua_pushliteral(L, "hello"); lua.lua_setglobal(L, to_luastring("js")); lua.lua_call(L, 0, 1); }, "JS Lua program ran without error"); t.strictEqual( lua.lua_tojsstring(L, -1), "hello world", "Correct element(s) on the stack" ); }); test('lua_createtable', function (t) { let L; t.plan(2); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lua.lua_createtable(L, 3, 3); }, "JS Lua program ran without error"); t.ok( lua.lua_istable(L, -1), "Correct element(s) on the stack" ); }); test('lua_newtable', function (t) { let L; t.plan(2); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); lua.lua_newtable(L); }, "JS Lua program ran without error"); t.ok( lua.lua_istable(L, -1), "Correct element(s) on the stack" ); }); test('lua_settable, lua_gettable', function (t) { let L; t.plan(2); t.doesNotThrow(function () { L = lauxlib.luaL_newstate(); 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); }, "JS Lua program ran without error"); t.strictEqual( lua.lua_tojsstring(L, -1), "value", "Correct element(s) on the stack" ); }); test('lua_atnativeerror', function(t) { t.plan(7); let L = lauxlib.luaL_newstate(); let errob = {}; lua.lua_pushcfunction(L, function(L) { throw errob; }); t.strictEqual(lua.lua_pcall(L, 0, 0, 0), -1, "without a native error handler pcall should be -1"); lua.lua_pop(L, 1); lua.lua_atnativeerror(L, function(L) { let e = lua.lua_touserdata(L, 1); t.strictEqual(e, errob); lua.lua_pushstring(L, to_luastring("runtime error!")); return 1; }); lua.lua_pushcfunction(L, function(L) { throw errob; }); t.strictEqual(lua.lua_pcall(L, 0, 0, 0), lua.LUA_ERRRUN, "should return lua.LUA_ERRRUN"); t.strictEqual(lua.lua_tojsstring(L, -1), "runtime error!"); lua.lua_pop(L, 1); lua.lua_atnativeerror(L, function(L) { let e = lua.lua_touserdata(L, 1); t.strictEqual(e, errob); lauxlib.luaL_error(L, to_luastring("runtime error!")); }); lua.lua_pushcfunction(L, function(L) { throw errob; }); t.strictEqual(lua.lua_pcall(L, 0, 0, 0), lua.LUA_ERRRUN, "luaL_error from a native error handler should result in LUA_ERRRUN"); t.strictEqual(lua.lua_tojsstring(L, -1), "runtime error!"); lua.lua_pop(L, 1); });