| -- $Id: testes/events.lua $ |
| -- See Copyright Notice in file all.lua |
| |
| print('testing metatables') |
| |
| local debug = require'debug' |
| |
| X = 20; B = 30 |
| |
| _ENV = setmetatable({}, {__index=_G}) |
| |
| collectgarbage() |
| |
| X = X+10 |
| assert(X == 30 and _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=function(x) return x.name end}) |
| assert(getmetatable(a) == "xuxu") |
| assert(tostring(a) == "NAME") |
| -- cannot change a protected metatable |
| 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) |
| |
| |
| function f (t, i, e) |
| assert(not e) |
| local p = rawget(t, "parent") |
| return (p and p[i]+3), "dummy return" |
| end |
| |
| t.__index = f |
| |
| a.parent = {z=25, x=12, [4] = 24} |
| assert(a[1] == 10 and a.z == 28 and a[4] == 27 and a.x == "10") |
| |
| collectgarbage() |
| |
| a = setmetatable({}, t) |
| function f(t, i, v) rawset(t, i, v-3) end |
| setmetatable(t, t) -- causes a bug in 5.1 ! |
| t.__newindex = f |
| a[1] = 30; a.x = "101"; a[5] = 200 |
| assert(a[1] == 27 and a.x == 98 and a[5] == 197) |
| |
| do -- bug in Lua 5.3.2 |
| local mt = {} |
| mt.__newindex = mt |
| local t = setmetatable({}, mt) |
| t[1] = 10 -- will segfault on some machines |
| assert(mt[1] == 10) |
| end |
| |
| |
| local c = {} |
| a = setmetatable({}, t) |
| t.__newindex = c |
| t.__index = c |
| a[1] = 10; a[2] = 20; a[3] = 90; |
| for i = 4, 20 do a[i] = i * 10 end |
| assert(a[1] == 10 and a[2] == 20 and a[3] == 90) |
| for i = 4, 20 do assert(a[i] == i * 10) end |
| assert(next(a) == nil) |
| |
| |
| do |
| local a; |
| a = setmetatable({}, {__index = setmetatable({}, |
| {__index = setmetatable({}, |
| {__index = function (_,n) return a[n-3]+4, "lixo" end})})}) |
| a[0] = 20 |
| for i=0,10 do |
| assert(a[i*3] == 20 + i*4) |
| end |
| end |
| |
| |
| do -- newindex |
| local foi |
| local a = {} |
| for i=1,10 do a[i] = 0; a['a'..i] = 0; end |
| setmetatable(a, {__newindex = function (t,k,v) foi=true; rawset(t,k,v) end}) |
| foi = false; a[1]=0; assert(not foi) |
| foi = false; a['a1']=0; assert(not foi) |
| foi = false; a['a11']=0; assert(foi) |
| foi = false; a[11]=0; assert(foi) |
| foi = false; a[1]=undef; assert(not foi) |
| a[1] = undef |
| foi = false; a[1]=nil; assert(foi) |
| end |
| |
| |
| setmetatable(t, nil) |
| function f (t, ...) return t, {...} end |
| t.__call = f |
| |
| do |
| local x,y = a(table.unpack{'a', 1}) |
| assert(x==a and y[1]=='a' and y[2]==1 and y[3]==undef) |
| x,y = a() |
| assert(x==a and y[1]==undef) |
| end |
| |
| |
| local b = setmetatable({}, t) |
| setmetatable(b,t) |
| |
| function f(op) |
| return function (...) cap = {[0] = op, ...} ; return (...) end |
| end |
| 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") |
| |
| -- Some tests are done inside small anonymous functions to ensure |
| -- that constants go to constant table even in debug compilation, |
| -- when the constant table is very small. |
| assert(b+5 == b) |
| assert(cap[0] == "add" and cap[1] == b and cap[2] == 5 and cap[3]==undef) |
| assert(b+'5' == b) |
| assert(cap[0] == "add" and cap[1] == b and cap[2] == '5' and cap[3]==undef) |
| assert(5+b == 5) |
| assert(cap[0] == "add" and cap[1] == 5 and cap[2] == b and cap[3]==undef) |
| assert('5'+b == '5') |
| assert(cap[0] == "add" and cap[1] == '5' and cap[2] == b and cap[3]==undef) |
| b=b-3; assert(getmetatable(b) == t) |
| assert(cap[0] == "sub" and cap[1] == b and cap[2] == 3 and cap[3]==undef) |
| assert(5-a == 5) |
| assert(cap[0] == "sub" and cap[1] == 5 and cap[2] == a and cap[3]==undef) |
| assert('5'-a == '5') |
| assert(cap[0] == "sub" and cap[1] == '5' and cap[2] == a and cap[3]==undef) |
| assert(a*a == a) |
| assert(cap[0] == "mul" and cap[1] == a and cap[2] == a and cap[3]==undef) |
| assert(a/0 == a) |
| assert(cap[0] == "div" and cap[1] == a and cap[2] == 0 and cap[3]==undef) |
| assert(a%2 == a) |
| assert(cap[0] == "mod" and cap[1] == a and cap[2] == 2 and cap[3]==undef) |
| assert(a // (1/0) == a) |
| assert(cap[0] == "idiv" and cap[1] == a and cap[2] == 1/0 and cap[3]==undef) |
| ;(function () assert(a & "hi" == a) end)() |
| assert(cap[0] == "band" and cap[1] == a and cap[2] == "hi" and cap[3]==undef) |
| ;(function () assert(10 & a == 10) end)() |
| assert(cap[0] == "band" and cap[1] == 10 and cap[2] == a and cap[3]==undef) |
| ;(function () assert(a | 10 == a) end)() |
| assert(cap[0] == "bor" and cap[1] == a and cap[2] == 10 and cap[3]==undef) |
| assert(a | "hi" == a) |
| assert(cap[0] == "bor" and cap[1] == a and cap[2] == "hi" and cap[3]==undef) |
| assert("hi" ~ a == "hi") |
| assert(cap[0] == "bxor" and cap[1] == "hi" and cap[2] == a and cap[3]==undef) |
| ;(function () assert(10 ~ a == 10) end)() |
| assert(cap[0] == "bxor" and cap[1] == 10 and cap[2] == a and cap[3]==undef) |
| assert(-a == a) |
| assert(cap[0] == "unm" and cap[1] == a) |
| assert(a^4 == a) |
| assert(cap[0] == "pow" and cap[1] == a and cap[2] == 4 and cap[3]==undef) |
| assert(a^'4' == a) |
| assert(cap[0] == "pow" and cap[1] == a and cap[2] == '4' and cap[3]==undef) |
| assert(4^a == 4) |
| assert(cap[0] == "pow" and cap[1] == 4 and cap[2] == a and cap[3]==undef) |
| assert('4'^a == '4') |
| assert(cap[0] == "pow" and cap[1] == '4' and cap[2] == a and cap[3]==undef) |
| assert(#a == a) |
| assert(cap[0] == "len" and cap[1] == a) |
| assert(~a == a) |
| assert(cap[0] == "bnot" and cap[1] == a) |
| assert(a << 3 == a) |
| assert(cap[0] == "shl" and cap[1] == a and cap[2] == 3) |
| assert(1.5 >> a == 1.5) |
| assert(cap[0] == "shr" and cap[1] == 1.5 and cap[2] == a) |
| |
| |
| -- test for rawlen |
| t = setmetatable({1,2,3}, {__len = function () return 10 end}) |
| assert(#t == 10 and rawlen(t) == 3) |
| assert(rawlen"abc" == 3) |
| assert(not pcall(rawlen, io.stdin)) |
| assert(not pcall(rawlen, 34)) |
| assert(not pcall(rawlen)) |
| |
| -- rawlen for long strings |
| assert(rawlen(string.rep('a', 1000)) == 1000) |
| |
| |
| t = {} |
| t.__lt = function (a,b,c) |
| collectgarbage() |
| assert(c == nil) |
| if type(a) == 'table' then a = a.x end |
| if type(b) == 'table' then b = b.x end |
| return a<b, "dummy" |
| end |
| |
| function Op(x) return setmetatable({x=x}, t) end |
| |
| local function test () |
| assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1))) |
| assert(not(1 < Op(1)) and (Op(1) < 2) and not(2 < Op(1))) |
| assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a'))) |
| assert(not('a' < Op('a')) and (Op('a') < 'b') and not(Op('b') < Op('a'))) |
| assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1))) |
| assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a'))) |
| assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1))) |
| assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a'))) |
| assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1))) |
| assert((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1)) |
| assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a'))) |
| assert(('a' >= Op('a')) and not(Op('a') >= 'b') and (Op('b') >= Op('a'))) |
| end |
| |
| test() |
| |
| t.__le = function (a,b,c) |
| assert(c == nil) |
| if type(a) == 'table' then a = a.x end |
| if type(b) == 'table' then b = b.x end |
| return a<=b, "dummy" |
| end |
| |
| test() -- retest comparisons, now using both `lt' and `le' |
| |
| |
| -- test `partial order' |
| |
| 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] = undef |
| 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] = undef |
| 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}] == undef) |
| |
| |
| if not T then |
| (Message or 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 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 |
| |
| local mirror = {} |
| debug.setmetatable(u3, {__index = mirror, __newindex = mirror}) |
| for i = 1, 10 do u3[i] = i end |
| for i = 1, 10 do assert(u3[i] == i) end |
| end |
| |
| |
| t.__concat = function (a,b,c) |
| assert(c == nil) |
| if type(a) == 'table' then a = a.val end |
| if type(b) == 'table' then b = b.val end |
| if A then return a..b |
| else |
| return setmetatable({val=a..b}, t) |
| end |
| end |
| |
| 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 and x.val == 'cd') |
| x = 0 .."a".."b"..c..d.."e".."f".."g" |
| assert(x.val == "0abcdefg") |
| |
| |
| -- concat metamethod x numbers (bug in 5.1.1) |
| c = {} |
| local x |
| setmetatable(c, {__concat = function (a,b) |
| assert(type(a) == "number" and b == c or type(b) == "number" and a == c) |
| return c |
| end}) |
| assert(c..5 == c and 5 .. c == c) |
| assert(4 .. c .. 5 == c and 4 .. 5 .. 6 .. 7 .. c == c) |
| |
| |
| -- test comparison compatibilities |
| local t1, t2, c, d |
| t1 = {}; c = {}; setmetatable(c, t1) |
| d = {} |
| t1.__eq = function () return true end |
| t1.__lt = function () return true end |
| setmetatable(d, t1) |
| assert(c == d and c < d and not(d <= c)) |
| t2 = {} |
| t2.__eq = t1.__eq |
| t2.__lt = t1.__lt |
| setmetatable(d, t2) |
| assert(c == d and c < d and not(d <= c)) |
| |
| |
| |
| -- test for several levels of calls |
| local i |
| local tt = { |
| __call = function (t, ...) |
| i = i+1 |
| if t.f then return t.f(...) |
| else return {...} |
| end |
| end |
| } |
| |
| 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 and x[1] == 3 and x[3] == 5) |
| |
| |
| assert(_G.X == 20) |
| |
| print'+' |
| |
| local _g = _G |
| _ENV = setmetatable({}, {__index=function (_,k) return _g[k] end}) |
| |
| |
| a = {} |
| rawset(a, "x", 1, 2, 3) |
| assert(a.x == 1 and rawget(a, "x", 3) == 1) |
| |
| print '+' |
| |
| -- testing metatables for basic types |
| mt = {__index = function (a,b) return a+b end, |
| __len = function (x) return math.floor(x) end} |
| 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 = function (a,b) return a or b end |
| 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 = function (a,b) return (a or 1) + (b or 2) end |
| assert(10 + nil == 12) |
| assert(nil + 23 == 24) |
| assert(nil + nil == 3) |
| debug.setmetatable(nil, nil) |
| assert(getmetatable(nil) == nil) |
| |
| debug.setmetatable(nil, {}) |
| |
| |
| -- loops in delegation |
| a = {}; setmetatable(a, a); a.__index = a; a.__newindex = a |
| assert(not pcall(function (a,b) return a[b] end, a, 10)) |
| assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true)) |
| |
| -- bug in 5.1 |
| T, K, V = nil |
| grandparent = {} |
| grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end |
| |
| parent = {} |
| parent.__newindex = parent |
| setmetatable(parent, grandparent) |
| |
| child = setmetatable({}, parent) |
| child.foo = 10 --> CRASH (on some machines) |
| assert(T == parent and K == "foo" and V == 10) |
| |
| print 'OK' |
| |
| return 12 |
| |
| |