--- source: src/main.rs assertion_line: 136 expression: compiled input_file: test-data/lua5.4-tests/events.lua --- print('testing metatables'); local debug = require('debug') X = 20 B = 30 _ENV = setmetatable({}, { __index = _G }) collectgarbage(); X = X + 10 assert(X == 30 && _G.X == 20); B = false assert(B == false); _ENV[("B")] = undef assert(B == 30); assert(getmetatable({}) == nil); assert(getmetatable(4) == nil); assert(getmetatable(nil) == nil); a = { name = "NAME" } setmetatable(a, { __metatable = "xuxu", __tostring = fn (x) { return x.name } }); assert(getmetatable(a) == "xuxu"); assert(tostring(a) == "NAME"); assert(pcall(setmetatable, a, {}) == false); a.name = "gororoba" assert(tostring(a) == "gororoba"); local a, t = { 10, 20, 30, x = "10", y = "20" }, {} assert(setmetatable(a, t) == a); assert(getmetatable(a) == t); assert(setmetatable(a, nil) == a); assert(getmetatable(a) == nil); assert(setmetatable(a, t) == a); global fn f(t, i, e) { assert(!e); local p = rawget(t, "parent") return (p && p[(i)] + 3), "dummy return" } t.__index = f a.parent = { z = 25, x = 12, 4 = 24 } assert(a[(1)] == 10 && a.z == 28 && a[(4)] == 27 && a.x == "10"); collectgarbage(); a = setmetatable({}, t) global fn f(t, i, v) { rawset(t, i, v - 3); } setmetatable(t, t); t.__newindex = f a[(1)] = 30 a.x = "101" a[(5)] = 200 assert(a[(1)] == 27 && a.x == 98 && a[(5)] == 197); { local mt = {} mt.__newindex = mt local t = setmetatable({}, mt) t[(1)] = 10 assert(mt[(1)] == 10); } local c = {} a = setmetatable({}, t) t.__newindex = c t.__index = c a[(1)] = 10 a[(2)] = 20 a[(3)] = 90 for i = 4, 20 { a[(i)] = i * 10 } assert(a[(1)] == 10 && a[(2)] == 20 && a[(3)] == 90); for i = 4, 20 { assert(a[(i)] == i * 10); } assert(next(a) == nil); { local a a = setmetatable({}, { __index = setmetatable({}, { __index = setmetatable({}, { __index = fn (_, n) { return a[(n - 3)] + 4, "lixo" } }) }) }) a[(0)] = 20 for i = 0, 10 { assert(a[(i * 3)] == 20 + i * 4); } } { local foi local a = {} for i = 1, 10 { a[(i)] = 0 a[('a' .. i)] = 0 } setmetatable(a, { __newindex = fn (t, k, v) { foi = true rawset(t, k, v); } }); foi = false a[(1)] = 0 assert(!foi); foi = false a[('a1')] = 0 assert(!foi); foi = false a[('a11')] = 0 assert(foi); foi = false a[(11)] = 0 assert(foi); foi = false a[(1)] = undef assert(!foi); a[(1)] = undef foi = false a[(1)] = nil assert(foi); } setmetatable(t, nil); global fn f(t, ...) { return t, { ... } } t.__call = f { local x, y = a(table.unpack({ 'a', 1 })) assert(x == a && y[(1)] == 'a' && y[(2)] == 1 && y[(3)] == undef); x, y = a() assert(x == a && y[(1)] == undef); } local b = setmetatable({}, t) setmetatable(b, t); global fn f(op) { return fn (...) { cap = { 0 = op, ... } return (...) } } t.__add = f("add") t.__sub = f("sub") t.__mul = f("mul") t.__div = f("div") t.__idiv = f("idiv") t.__mod = f("mod") t.__unm = f("unm") t.__pow = f("pow") t.__len = f("len") t.__band = f("band") t.__bor = f("bor") t.__bxor = f("bxor") t.__shl = f("shl") t.__shr = f("shr") t.__bnot = f("bnot") t.__lt = f("lt") t.__le = f("le") local fn checkcap(t) { assert(#cap + 1 == #t); for i = 1, #t { assert(cap[(i - 1)] == t[(i)]); assert(math.type(cap[(i - 1)]) == math.type(t[(i)])); } } assert(b + 5 == b); checkcap({ "add", b, 5 }); assert(5.2 + b == 5.2); checkcap({ "add", 5.2, b }); assert(b + '5' == b); checkcap({ "add", b, '5' }); assert(5 + b == 5); checkcap({ "add", 5, b }); assert('5' + b == '5'); checkcap({ "add", '5', b }); b = b - 3 assert(getmetatable(b) == t); checkcap({ "sub", b, 3 }); assert(5 - a == 5); checkcap({ "sub", 5, a }); assert('5' - a == '5'); checkcap({ "sub", '5', a }); assert(a * a == a); checkcap({ "mul", a, a }); assert(a / 0 == a); checkcap({ "div", a, 0 }); assert(a / 0.0 == a); checkcap({ "div", a, 0.0 }); assert(a % 2 == a); checkcap({ "mod", a, 2 }); assert(a /_ (1 / 0) == a); checkcap({ "idiv", a, 1 / 0 }); (fn () { assert(a & "hi" == a); })(); checkcap({ "band", a, "hi" }); (fn () { assert(10 & a == 10); })(); checkcap({ "band", 10, a }); (fn () { assert(a | 10 == a); })(); checkcap({ "bor", a, 10 }); assert(a | "hi" == a); checkcap({ "bor", a, "hi" }); assert("hi" ^^ a == "hi"); checkcap({ "bxor", "hi", a }); (fn () { assert(10 ^^ a == 10); })(); checkcap({ "bxor", 10, a }); assert(-a == a); checkcap({ "unm", a, a }); assert(a ^ 4.0 == a); checkcap({ "pow", a, 4.0 }); assert(a ^ '4' == a); checkcap({ "pow", a, '4' }); assert(4 ^ a == 4); checkcap({ "pow", 4, a }); assert('4' ^ a == '4'); checkcap({ "pow", '4', a }); assert(#a == a); checkcap({ "len", a, a }); assert(~a == a); checkcap({ "bnot", a, a }); assert(a << 3 == a); checkcap({ "shl", a, 3 }); assert(1.5 >> a == 1.5); checkcap({ "shr", 1.5, a }); assert(5.0 > a); checkcap({ "lt", a, 5.0 }); assert(a >= 10); checkcap({ "le", 10, a }); assert(a <= -10.0); checkcap({ "le", a, -10.0 }); assert(a < -10); checkcap({ "lt", a, -10 }); t = setmetatable({ 1, 2, 3 }, { __len = fn () { return 10 } }) assert(#t == 10 && rawlen(t) == 3); assert(rawlen("abc") == 3); assert(!pcall(rawlen, io.stdin)); assert(!pcall(rawlen, 34)); assert(!pcall(rawlen)); assert(rawlen(string.rep('a', 1000)) == 1000); t = {} t.__lt = fn (a, b, c) { collectgarbage(); assert(c == nil); if type(a) == 'table' { a = a.x } if type(b) == 'table' { b = b.x } return a < b, "dummy" } t.__le = fn (a, b, c) { assert(c == nil); if type(a) == 'table' { a = a.x } if type(b) == 'table' { b = b.x } return a <= b, "dummy" } t.__eq = fn (a, b, c) { assert(c == nil); if type(a) == 'table' { a = a.x } if type(b) == 'table' { b = b.x } return a == b, "dummy" } global fn Op(x) { return setmetatable({ x = x }, t) } local fn test(a, b, c) { assert(!(Op(1) < Op(1)) && (Op(1) < Op(2)) && !(Op(2) < Op(1))); assert(!(1 < Op(1)) && (Op(1) < 2) && !(2 < Op(1))); assert(!(Op('a') < Op('a')) && (Op('a') < Op('b')) && !(Op('b') < Op('a'))); assert(!('a' < Op('a')) && (Op('a') < 'b') && !(Op('b') < Op('a'))); assert((Op(1) <= Op(1)) && (Op(1) <= Op(2)) && !(Op(2) <= Op(1))); assert((Op('a') <= Op('a')) && (Op('a') <= Op('b')) && !(Op('b') <= Op('a'))); assert(!(Op(1) > Op(1)) && !(Op(1) > Op(2)) && (Op(2) > Op(1))); assert(!(Op('a') > Op('a')) && !(Op('a') > Op('b')) && (Op('b') > Op('a'))); assert((Op(1) >= Op(1)) && !(Op(1) >= Op(2)) && (Op(2) >= Op(1))); assert((1 >= Op(1)) && !(1 >= Op(2)) && (Op(2) >= 1)); assert((Op('a') >= Op('a')) && !(Op('a') >= Op('b')) && (Op('b') >= Op('a'))); assert(('a' >= Op('a')) && !(Op('a') >= 'b') && (Op('b') >= Op('a'))); assert(Op(1) == Op(1) && Op(1) != Op(2)); assert(Op('a') == Op('a') && Op('a') != Op('b')); assert(a == a && a != b); assert(Op(3) == c); } test(Op(1), Op(2), Op(3)); local fn rawSet(x) { local y = {} for _, k with pairs(x) { y[(k)] = 1 } return y } local fn Set(x) { return setmetatable(rawSet(x), t) } t.__lt = fn (a, b) { for k with pairs(a) { if !b[(k)] { return false } b[(k)] = undef } return next(b) != nil } t.__le = fn (a, b) { for k with pairs(a) { if !b[(k)] { return false } } return true } assert(Set({ 1, 2, 3 }) < 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, 2, 3, 4 }) >= Set({ 1, 2, 3, 4 }))); assert(!(Set({ 1, 3 }) <= Set({ 3, 5 }))); assert(!(Set({ 1, 3 }) <= Set({ 3, 5 }))); assert(!(Set({ 1, 3 }) >= Set({ 3, 5 }))); t.__eq = fn (a, b) { for k with pairs(a) { if !b[(k)] { return false } b[(k)] = undef } return next(b) == nil } local s = Set({ 1, 3, 5 }) assert(s == Set({ 3, 5, 1 })); assert(!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 })); t[(Set({ 1, 3, 5 }))] = 1 assert(t[(Set({ 1, 3, 5 }))] == undef); { local mt = { __eq = true } local a = setmetatable({ 10 }, mt) local b = setmetatable({ 10 }, mt) mt.__eq = nil assert(a != b); mt.__eq = fn (x, y) { return x[(1)] == y[(1)] } assert(a == b); } if !T { (Message || print)('\n >>> testC not active: skipping tests for \z userdata <<<\n'); } else { local u1 = T.newuserdata(0, 1) local u2 = T.newuserdata(0, 1) local u3 = T.newuserdata(0, 1) assert(u1 != u2 && u1 != u3); debug.setuservalue(u1, 1); debug.setuservalue(u2, 2); debug.setuservalue(u3, 1); debug.setmetatable(u1, { __eq = fn (a, b) { return debug.getuservalue(a) == debug.getuservalue(b) } }); debug.setmetatable(u2, { __eq = fn (a, b) { return true } }); assert(u1 == u3 && u3 == u1 && u1 != u2); assert(u2 == u1 && u2 == u3 && u3 == u2); assert(u2 != {}); assert(rawequal(u1, u1) && !rawequal(u1, u3)); local mirror = {} debug.setmetatable(u3, { __index = mirror, __newindex = mirror }); for i = 1, 10 { u3[(i)] = i } for i = 1, 10 { assert(u3[(i)] == i); } } t.__concat = fn (a, b, c) { assert(c == nil); if type(a) == 'table' { a = a.val } if type(b) == 'table' { b = b.val } if A { return a .. b } else { return setmetatable({ val = a .. b }, t) } } c = { val = "c" } setmetatable(c, t); d = { val = "d" } setmetatable(d, t); A = true assert(c .. d == 'cd'); assert(0 .. "a" .. "b" .. c .. d .. "e" .. "f" .. (5 + 3) .. "g" == "0abcdef8g"); A = false assert((c .. d .. c .. d).val == 'cdcd'); x = c .. d assert(getmetatable(x) == t && x.val == 'cd'); x = 0 .. "a" .. "b" .. c .. d .. "e" .. "f" .. "g" assert(x.val == "0abcdefg"); c = {} local x setmetatable(c, { __concat = fn (a, b) { assert(type(a) == "number" && b == c || type(b) == "number" && a == c); return c } }); assert(c .. 5 == c && 5 .. c == c); assert(4 .. c .. 5 == c && 4 .. 5 .. 6 .. 7 .. c == c); local t1, t2, c, d t1 = {} c = {} setmetatable(c, t1); d = {} t1.__eq = fn () { return true } t1.__lt = fn () { return true } t1.__le = fn () { return false } setmetatable(d, t1); assert(c == d && c < d && !(d <= c)); t2 = {} t2.__eq = t1.__eq t2.__lt = t1.__lt setmetatable(d, t2); assert(c == d && c < d && !(d <= c)); local i local tt = { __call = fn (t, ...) { i = i + 1 if t.f { return t.f(...) } else { return { ... } } } } local a = setmetatable({}, tt) local b = setmetatable({ f = a }, tt) local c = setmetatable({ f = b }, tt) i = 0 x = c(3, 4, 5) assert(i == 3 && x[(1)] == 3 && x[(3)] == 5); assert(_G.X == 20); print('+'); local _g = _G _ENV = setmetatable({}, { __index = fn (_, k) { return _g[(k)] } }) a = {} rawset(a, "x", 1, 2, 3); assert(a.x == 1 && rawget(a, "x", 3) == 1); print('+'); mt = { __index = fn (a, b) { return a + b }, __len = fn (x) { return math.floor(x) } } debug.setmetatable(10, mt); assert(getmetatable(-2) == mt); assert((10)[(3)] == 13); assert((10)[("3")] == 13); assert(#3.45 == 3); debug.setmetatable(23, nil); assert(getmetatable(-2) == nil); debug.setmetatable(true, mt); assert(getmetatable(false) == mt); mt.__index = fn (a, b) { return a || b } assert((true)[(false)] == true); assert((false)[(false)] == false); debug.setmetatable(false, nil); assert(getmetatable(true) == nil); debug.setmetatable(nil, mt); assert(getmetatable(nil) == mt); mt.__add = fn (a, b) { return (a || 1) + (b || 2) } assert(10 + nil == 12); assert(nil + 23 == 24); assert(nil + nil == 3); debug.setmetatable(nil, nil); assert(getmetatable(nil) == nil); debug.setmetatable(nil, {}); a = {} setmetatable(a, a); a.__index = a a.__newindex = a assert(!pcall(fn (a, b) { return a[(b)] }, a, 10)); assert(!pcall(fn (a, b, c) { a[(b)] = c }, a, 10, true)); T, K, V = nil grandparent = {} grandparent.__newindex = fn (t, k, v) { T = t K = k V = v } parent = {} parent.__newindex = parent setmetatable(parent, grandparent); child = setmetatable({}, parent) child.foo = 10 assert(T == parent && K == "foo" && V == 10); print('OK'); return 12