diff options
-rw-r--r-- | src/lapi.js | 6 | ||||
-rw-r--r-- | src/ltable.js | 2 | ||||
-rw-r--r-- | tests/test-suite/events.js | 131 | ||||
-rw-r--r-- | tests/test-suite/ltests.js | 34 |
4 files changed, 169 insertions, 4 deletions
diff --git a/src/lapi.js b/src/lapi.js index a5cfb8d..9fc1cc7 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -496,7 +496,7 @@ const luaS_newudata = function(L, size) { return { id: L.l_G.id_counter++, metatable: null, - uservalue: null, + uservalue: new lobject.TValue(CT.LUA_TNIL, null), len: size, data: Object.create(null) // ignores size argument }; @@ -595,7 +595,7 @@ const lua_getmetatable = function(L, objindex) { const lua_getuservalue = function(L, idx) { let o = index2addr(L, idx); assert(L, o.ttisfulluserdata(), "full userdata expected"); - let uv = o.uservalue; + let uv = o.value.uservalue; L.stack[L.top++] = new TValue(uv.type, uv.value); assert(L.top <= L.ci.top, "stack overflow"); return L.stack[L.top - 1].ttnov(); @@ -895,7 +895,7 @@ const lua_setuservalue = function(L, idx) { assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack"); let o = index2addr(L, idx); assert(L, o.ttisfulluserdata(), "full userdata expected"); - o.uservalue.setfrom(L.stack[L.top - 1]); + o.value.uservalue.setfrom(L.stack[L.top - 1]); delete L.stack[--L.top]; }; diff --git a/src/ltable.js b/src/ltable.js index 52b5aee..0619efe 100644 --- a/src/ltable.js +++ b/src/ltable.js @@ -158,7 +158,7 @@ const luaH_next = function(L, table, keyI) { if (!table.strong.has(hash)) /* item not in table */ - return ldebug.luaG_runerror(L, "invalid key to 'next'"); + return ldebug.luaG_runerror(L, defs.to_luastring("invalid key to 'next'")) let indexes = table.strong.keys(); while (1) { diff --git a/tests/test-suite/events.js b/tests/test-suite/events.js index d7dfe15..8aa7aa7 100644 --- a/tests/test-suite/events.js +++ b/tests/test-suite/events.js @@ -8,6 +8,8 @@ const lua = require('../../src/lua.js'); const lauxlib = require('../../src/lauxlib.js'); const lualib = require('../../src/lualib.js'); +const ltests = require('./ltests.js'); + test("[test-suite] events: testing metatable", function (t) { let luaCode = ` @@ -297,3 +299,132 @@ test("[test-suite] events: test comparison", function (t) { }, "Lua program ran without error"); }); + + +// TODO: uncomment asserts when next is fixed for cleared table entries +test("[test-suite] events: test 'partial order'", function (t) { + let luaCode = ` + t = {} + + local function rawSet(x) + local y = {} + for _,k in pairs(x) do y[k] = 1 end + return y + end + + local function Set(x) + return setmetatable(rawSet(x), t) + end + + t.__lt = function (a,b) + for k in pairs(a) do + if not b[k] then return false end + b[k] = nil + end + return next(b) ~= nil + end + + t.__le = nil + + assert(Set{1,2,3} < Set{1,2,3,4}) + -- assert(not(Set{1,2,3,4} < Set{1,2,3,4})) + -- assert((Set{1,2,3,4} <= Set{1,2,3,4})) + -- assert((Set{1,2,3,4} >= Set{1,2,3,4})) + assert((Set{1,3} <= Set{3,5})) -- wrong!! model needs a 'le' method ;-) + + t.__le = function (a,b) + for k in pairs(a) do + if not b[k] then return false end + end + return true + end + + assert(not (Set{1,3} <= Set{3,5})) -- now its OK! + assert(not(Set{1,3} <= Set{3,5})) + assert(not(Set{1,3} >= Set{3,5})) + + t.__eq = function (a,b) + for k in pairs(a) do + if not b[k] then return false end + b[k] = nil + end + return next(b) == nil + end + + local s = Set{1,3,5} + -- assert(s == Set{3,5,1}) + assert(not rawequal(s, Set{3,5,1})) + assert(rawequal(s, s)) + -- assert(Set{1,3,5,1} == rawSet{3,5,1}) + -- assert(rawSet{1,3,5,1} == Set{3,5,1}) + assert(Set{1,3,5} ~= Set{3,5,1,6}) + + -- '__eq' is not used for table accesses + t[Set{1,3,5}] = 1 + assert(t[Set{1,3,5}] == nil) + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + lualib.luaL_openlibs(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lua.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + +}); + + +test("[test-suite] events: __eq between userdata", function (t) { + let luaCode = ` + T = require('T') + + local u1 = T.newuserdata(0) + local u2 = T.newuserdata(0) + local u3 = T.newuserdata(0) + assert(u1 ~= u2 and u1 ~= u3) + debug.setuservalue(u1, 1); + debug.setuservalue(u2, 2); + debug.setuservalue(u3, 1); + debug.setmetatable(u1, {__eq = function (a, b) + return debug.getuservalue(a) == debug.getuservalue(b) + end}) + debug.setmetatable(u2, {__eq = function (a, b) + return true + end}) + assert(u1 == u3 and u3 == u1 and u1 ~= u2) + assert(u2 == u1 and u2 == u3 and u3 == u2) + assert(u2 ~= {}) -- different types cannot be equal + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + lualib.luaL_openlibs(L); + + ltests.luaopen_tests(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lua.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + +}); diff --git a/tests/test-suite/ltests.js b/tests/test-suite/ltests.js new file mode 100644 index 0000000..b4b575b --- /dev/null +++ b/tests/test-suite/ltests.js @@ -0,0 +1,34 @@ +"use strict"; + +global.WEB = false; + +const lua = require('../../src/lua.js'); +const lauxlib = require('../../src/lauxlib.js'); + + +const tpanic = function(L) { + console.error(`PANIC: unprotected error in call to Lua API (${lua.lua_tojsstring(L, -1)})\n`); + return process.exit(1); /* do not return to Lua */ +}; + +const newuserdata = function(L) { + lua.lua_newuserdata(L, lauxlib.luaL_checkinteger(L, 1)); + return 1; +}; + +const tests_funcs = { + "newuserdata": newuserdata +}; + +const luaB_opentests = function(L) { + lua.lua_atpanic(L, tpanic); + lauxlib.luaL_newlib(L, tests_funcs); + return 1; +}; + +const luaopen_tests = function(L) { + lauxlib.luaL_requiref(L, lua.to_luastring("T"), luaB_opentests, 1); + lua.lua_pop(L, 1); /* remove lib */ +}; + +module.exports.luaopen_tests = luaopen_tests; |