aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lapi.js6
-rw-r--r--src/ltable.js2
-rw-r--r--tests/test-suite/events.js131
-rw-r--r--tests/test-suite/ltests.js34
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;