lua

A copy of the Lua development repository
Log | Files | Refs | README

events.lua (12589B)


      1 -- $Id: testes/events.lua $
      2 -- See Copyright Notice in file all.lua
      3 
      4 print('testing metatables')
      5 
      6 local debug = require'debug'
      7 
      8 X = 20; B = 30
      9 
     10 _ENV = setmetatable({}, {__index=_G})
     11 
     12 collectgarbage()
     13 
     14 X = X+10
     15 assert(X == 30 and _G.X == 20)
     16 B = false
     17 assert(B == false)
     18 _ENV["B"] = undef
     19 assert(B == 30)
     20 
     21 assert(getmetatable{} == nil)
     22 assert(getmetatable(4) == nil)
     23 assert(getmetatable(nil) == nil)
     24 a={name = "NAME"}; setmetatable(a, {__metatable = "xuxu",
     25                     __tostring=function(x) return x.name end})
     26 assert(getmetatable(a) == "xuxu")
     27 assert(tostring(a) == "NAME")
     28 -- cannot change a protected metatable
     29 assert(pcall(setmetatable, a, {}) == false)
     30 a.name = "gororoba"
     31 assert(tostring(a) == "gororoba")
     32 
     33 local a, t = {10,20,30; x="10", y="20"}, {}
     34 assert(setmetatable(a,t) == a)
     35 assert(getmetatable(a) == t)
     36 assert(setmetatable(a,nil) == a)
     37 assert(getmetatable(a) == nil)
     38 assert(setmetatable(a,t) == a)
     39 
     40 
     41 function f (t, i, e)
     42   assert(not e)
     43   local p = rawget(t, "parent")
     44   return (p and p[i]+3), "dummy return"
     45 end
     46 
     47 t.__index = f
     48 
     49 a.parent = {z=25, x=12, [4] = 24}
     50 assert(a[1] == 10 and a.z == 28 and a[4] == 27 and a.x == "10")
     51 
     52 collectgarbage()
     53 
     54 a = setmetatable({}, t)
     55 function f(t, i, v) rawset(t, i, v-3) end
     56 setmetatable(t, t)   -- causes a bug in 5.1 !
     57 t.__newindex = f
     58 a[1] = 30; a.x = "101"; a[5] = 200
     59 assert(a[1] == 27 and a.x == 98 and a[5] == 197)
     60 
     61 do    -- bug in Lua 5.3.2
     62   local mt = {}
     63   mt.__newindex = mt
     64   local t = setmetatable({}, mt)
     65   t[1] = 10     -- will segfault on some machines
     66   assert(mt[1] == 10)
     67 end
     68 
     69 
     70 local c = {}
     71 a = setmetatable({}, t)
     72 t.__newindex = c
     73 t.__index = c
     74 a[1] = 10; a[2] = 20; a[3] = 90;
     75 for i = 4, 20 do a[i] = i * 10 end
     76 assert(a[1] == 10 and a[2] == 20 and a[3] == 90)
     77 for i = 4, 20 do assert(a[i] == i * 10) end
     78 assert(next(a) == nil)
     79 
     80 
     81 do
     82   local a;
     83   a = setmetatable({}, {__index = setmetatable({},
     84                      {__index = setmetatable({},
     85                      {__index = function (_,n) return a[n-3]+4, "lixo" end})})})
     86   a[0] = 20
     87   for i=0,10 do
     88     assert(a[i*3] == 20 + i*4)
     89   end
     90 end
     91 
     92 
     93 do  -- newindex
     94   local foi
     95   local a = {}
     96   for i=1,10 do a[i] = 0; a['a'..i] = 0; end
     97   setmetatable(a, {__newindex = function (t,k,v) foi=true; rawset(t,k,v) end})
     98   foi = false; a[1]=0; assert(not foi)
     99   foi = false; a['a1']=0; assert(not foi)
    100   foi = false; a['a11']=0; assert(foi)
    101   foi = false; a[11]=0; assert(foi)
    102   foi = false; a[1]=undef; assert(not foi)
    103   a[1] = undef
    104   foi = false; a[1]=nil; assert(foi)
    105 end
    106 
    107 
    108 setmetatable(t, nil)
    109 function f (t, ...) return t, {...} end
    110 t.__call = f
    111 
    112 do
    113   local x,y = a(table.unpack{'a', 1})
    114   assert(x==a and y[1]=='a' and y[2]==1 and y[3]==undef)
    115   x,y = a()
    116   assert(x==a and y[1]==undef)
    117 end
    118 
    119 
    120 local b = setmetatable({}, t)
    121 setmetatable(b,t)
    122 
    123 function f(op)
    124   return function (...) cap = {[0] = op, ...} ; return (...) end
    125 end
    126 t.__add = f("add")
    127 t.__sub = f("sub")
    128 t.__mul = f("mul")
    129 t.__div = f("div")
    130 t.__idiv = f("idiv")
    131 t.__mod = f("mod")
    132 t.__unm = f("unm")
    133 t.__pow = f("pow")
    134 t.__len = f("len")
    135 t.__band = f("band")
    136 t.__bor = f("bor")
    137 t.__bxor = f("bxor")
    138 t.__shl = f("shl")
    139 t.__shr = f("shr")
    140 t.__bnot = f("bnot")
    141 t.__lt = f("lt")
    142 t.__le = f("le")
    143 
    144 
    145 local function checkcap (t)
    146   assert(#cap + 1 == #t)
    147   for i = 1, #t do
    148     assert(cap[i - 1] == t[i])
    149     assert(math.type(cap[i - 1]) == math.type(t[i]))
    150   end
    151 end
    152 
    153 -- Some tests are done inside small anonymous functions to ensure
    154 -- that constants go to constant table even in debug compilation,
    155 -- when the constant table is very small.
    156 assert(b+5 == b); checkcap{"add", b, 5}
    157 assert(5.2 + b == 5.2); checkcap{"add", 5.2, b}
    158 assert(b+'5' == b); checkcap{"add", b, '5'}
    159 assert(5+b == 5); checkcap{"add", 5, b}
    160 assert('5'+b == '5'); checkcap{"add", '5', b}
    161 b=b-3; assert(getmetatable(b) == t); checkcap{"sub", b, 3}
    162 assert(5-a == 5); checkcap{"sub", 5, a}
    163 assert('5'-a == '5'); checkcap{"sub", '5', a}
    164 assert(a*a == a); checkcap{"mul", a, a}
    165 assert(a/0 == a); checkcap{"div", a, 0}
    166 assert(a/0.0 == a); checkcap{"div", a, 0.0}
    167 assert(a%2 == a); checkcap{"mod", a, 2}
    168 assert(a // (1/0) == a); checkcap{"idiv", a, 1/0}
    169 ;(function () assert(a & "hi" == a) end)(); checkcap{"band", a, "hi"}
    170 ;(function () assert(10 & a  == 10) end)(); checkcap{"band", 10, a}
    171 ;(function () assert(a | 10  == a) end)(); checkcap{"bor", a, 10}
    172 assert(a | "hi" == a); checkcap{"bor", a, "hi"}
    173 assert("hi" ~ a == "hi"); checkcap{"bxor", "hi", a}
    174 ;(function () assert(10 ~ a == 10) end)(); checkcap{"bxor", 10, a}
    175 assert(-a == a); checkcap{"unm", a, a}
    176 assert(a^4.0 == a); checkcap{"pow", a, 4.0}
    177 assert(a^'4' == a); checkcap{"pow", a, '4'}
    178 assert(4^a == 4); checkcap{"pow", 4, a}
    179 assert('4'^a == '4'); checkcap{"pow", '4', a}
    180 assert(#a == a); checkcap{"len", a, a}
    181 assert(~a == a); checkcap{"bnot", a, a}
    182 assert(a << 3 == a); checkcap{"shl", a, 3}
    183 assert(1.5 >> a == 1.5); checkcap{"shr", 1.5, a}
    184 
    185 -- for comparison operators, all results are true
    186 assert(5.0 > a); checkcap{"lt", a, 5.0}
    187 assert(a >= 10); checkcap{"le", 10, a}
    188 assert(a <= -10.0); checkcap{"le", a, -10.0}
    189 assert(a < -10); checkcap{"lt", a, -10}
    190 
    191 
    192 -- test for rawlen
    193 t = setmetatable({1,2,3}, {__len = function () return 10 end})
    194 assert(#t == 10 and rawlen(t) == 3)
    195 assert(rawlen"abc" == 3)
    196 assert(not pcall(rawlen, io.stdin))
    197 assert(not pcall(rawlen, 34))
    198 assert(not pcall(rawlen))
    199 
    200 -- rawlen for long strings
    201 assert(rawlen(string.rep('a', 1000)) == 1000)
    202 
    203 
    204 t = {}
    205 t.__lt = function (a,b,c)
    206   collectgarbage()
    207   assert(c == nil)
    208   if type(a) == 'table' then a = a.x end
    209   if type(b) == 'table' then b = b.x end
    210  return a<b, "dummy"
    211 end
    212 
    213 t.__le = function (a,b,c)
    214   assert(c == nil)
    215   if type(a) == 'table' then a = a.x end
    216   if type(b) == 'table' then b = b.x end
    217  return a<=b, "dummy"
    218 end
    219 
    220 t.__eq = function (a,b,c)
    221   assert(c == nil)
    222   if type(a) == 'table' then a = a.x end
    223   if type(b) == 'table' then b = b.x end
    224  return a == b, "dummy"
    225 end
    226 
    227 function Op(x) return setmetatable({x=x}, t) end
    228 
    229 local function test (a, b, c)
    230   assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1)))
    231   assert(not(1 < Op(1)) and (Op(1) < 2) and not(2 < Op(1)))
    232   assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a')))
    233   assert(not('a' < Op('a')) and (Op('a') < 'b') and not(Op('b') < Op('a')))
    234   assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1)))
    235   assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a')))
    236   assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1)))
    237   assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a')))
    238   assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1)))
    239   assert((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1))
    240   assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a')))
    241   assert(('a' >= Op('a')) and not(Op('a') >= 'b') and (Op('b') >= Op('a')))
    242   assert(Op(1) == Op(1) and Op(1) ~= Op(2))
    243   assert(Op('a') == Op('a') and Op('a') ~= Op('b'))
    244   assert(a == a and a ~= b)
    245   assert(Op(3) == c)
    246 end
    247 
    248 test(Op(1), Op(2), Op(3))
    249 
    250 
    251 do  -- test nil as false
    252   local x = setmetatable({12}, {__eq= function (a,b)
    253     return a[1] == b[1] or nil
    254   end})
    255   assert(not (x == {20}))
    256   assert(x == {12})
    257 end
    258 
    259 
    260 -- test `partial order'
    261 
    262 local function rawSet(x)
    263   local y = {}
    264   for _,k in pairs(x) do y[k] = 1 end
    265   return y
    266 end
    267 
    268 local function Set(x)
    269   return setmetatable(rawSet(x), t)
    270 end
    271 
    272 t.__lt = function (a,b)
    273   for k in pairs(a) do
    274     if not b[k] then return false end
    275     b[k] = undef
    276   end
    277   return next(b) ~= nil
    278 end
    279 
    280 t.__le = function (a,b)
    281   for k in pairs(a) do
    282     if not b[k] then return false end
    283   end
    284   return true
    285 end
    286 
    287 assert(Set{1,2,3} < Set{1,2,3,4})
    288 assert(not(Set{1,2,3,4} < Set{1,2,3,4}))
    289 assert((Set{1,2,3,4} <= Set{1,2,3,4}))
    290 assert((Set{1,2,3,4} >= Set{1,2,3,4}))
    291 assert(not (Set{1,3} <= Set{3,5}))
    292 assert(not(Set{1,3} <= Set{3,5}))
    293 assert(not(Set{1,3} >= Set{3,5}))
    294 
    295 
    296 t.__eq = function (a,b)
    297   for k in pairs(a) do
    298     if not b[k] then return false end
    299     b[k] = undef
    300   end
    301   return next(b) == nil
    302 end
    303 
    304 local s = Set{1,3,5}
    305 assert(s == Set{3,5,1})
    306 assert(not rawequal(s, Set{3,5,1}))
    307 assert(rawequal(s, s))
    308 assert(Set{1,3,5,1} == rawSet{3,5,1})
    309 assert(rawSet{1,3,5,1} == Set{3,5,1})
    310 assert(Set{1,3,5} ~= Set{3,5,1,6})
    311 
    312 -- '__eq' is not used for table accesses
    313 t[Set{1,3,5}] = 1
    314 assert(t[Set{1,3,5}] == undef)
    315 
    316 
    317 do   -- test invalidating flags
    318   local mt = {__eq = true}
    319   local a = setmetatable({10}, mt)
    320   local b = setmetatable({10}, mt)
    321   mt.__eq = nil
    322   assert(a ~= b)   -- no metamethod
    323   mt.__eq = function (x,y) return x[1] == y[1] end
    324   assert(a == b)   -- must use metamethod now
    325 end
    326 
    327 
    328 if not T then
    329   (Message or print)('\n >>> testC not active: skipping tests for \z
    330 userdata <<<\n')
    331 else
    332   local u1 = T.newuserdata(0, 1)
    333   local u2 = T.newuserdata(0, 1)
    334   local u3 = T.newuserdata(0, 1)
    335   assert(u1 ~= u2 and u1 ~= u3)
    336   debug.setuservalue(u1, 1);
    337   debug.setuservalue(u2, 2);
    338   debug.setuservalue(u3, 1);
    339   debug.setmetatable(u1, {__eq = function (a, b)
    340     return debug.getuservalue(a) == debug.getuservalue(b)
    341   end})
    342   debug.setmetatable(u2, {__eq = function (a, b)
    343     return true
    344   end})
    345   assert(u1 == u3 and u3 == u1 and u1 ~= u2)
    346   assert(u2 == u1 and u2 == u3 and u3 == u2)
    347   assert(u2 ~= {})   -- different types cannot be equal
    348   assert(rawequal(u1, u1) and not rawequal(u1, u3))
    349 
    350   local mirror = {}
    351   debug.setmetatable(u3, {__index = mirror, __newindex = mirror})
    352   for i = 1, 10 do u3[i] = i end
    353   for i = 1, 10 do assert(u3[i] == i) end
    354 end
    355 
    356 
    357 t.__concat = function (a,b,c)
    358   assert(c == nil)
    359   if type(a) == 'table' then a = a.val end
    360   if type(b) == 'table' then b = b.val end
    361   if A then return a..b
    362   else
    363     return setmetatable({val=a..b}, t)
    364   end
    365 end
    366 
    367 c = {val="c"}; setmetatable(c, t)
    368 d = {val="d"}; setmetatable(d, t)
    369 
    370 A = true
    371 assert(c..d == 'cd')
    372 assert(0 .."a".."b"..c..d.."e".."f"..(5+3).."g" == "0abcdef8g")
    373 
    374 A = false
    375 assert((c..d..c..d).val == 'cdcd')
    376 x = c..d
    377 assert(getmetatable(x) == t and x.val == 'cd')
    378 x = 0 .."a".."b"..c..d.."e".."f".."g"
    379 assert(x.val == "0abcdefg")
    380 
    381 
    382 -- concat metamethod x numbers (bug in 5.1.1)
    383 c = {}
    384 local x
    385 setmetatable(c, {__concat = function (a,b)
    386   assert(type(a) == "number" and b == c or type(b) == "number" and a == c)
    387   return c
    388 end})
    389 assert(c..5 == c and 5 .. c == c)
    390 assert(4 .. c .. 5 == c and 4 .. 5 .. 6 .. 7 .. c == c)
    391 
    392 
    393 -- test comparison compatibilities
    394 local t1, t2, c, d
    395 t1 = {};  c = {}; setmetatable(c, t1)
    396 d = {}
    397 t1.__eq = function () return true end
    398 t1.__lt = function () return true end
    399 t1.__le = function () return false end
    400 setmetatable(d, t1)
    401 assert(c == d and c < d and not(d <= c))
    402 t2 = {}
    403 t2.__eq = t1.__eq
    404 t2.__lt = t1.__lt
    405 setmetatable(d, t2)
    406 assert(c == d and c < d and not(d <= c))
    407 
    408 
    409 
    410 -- test for several levels of calls
    411 local i
    412 local tt = {
    413   __call = function (t, ...)
    414     i = i+1
    415     if t.f then return t.f(...)
    416     else return {...}
    417     end
    418   end
    419 }
    420 
    421 local a = setmetatable({}, tt)
    422 local b = setmetatable({f=a}, tt)
    423 local c = setmetatable({f=b}, tt)
    424 
    425 i = 0
    426 x = c(3,4,5)
    427 assert(i == 3 and x[1] == 3 and x[3] == 5)
    428 
    429 
    430 assert(_G.X == 20)
    431 
    432 _G.X, _G.B = nil
    433 
    434 
    435 print'+'
    436 
    437 local _g = _G
    438 _ENV = setmetatable({}, {__index=function (_,k) return _g[k] end})
    439 
    440 
    441 a = {}
    442 rawset(a, "x", 1, 2, 3)
    443 assert(a.x == 1 and rawget(a, "x", 3) == 1)
    444 
    445 print '+'
    446 
    447 -- testing metatables for basic types
    448 mt = {__index = function (a,b) return a+b end,
    449       __len = function (x) return math.floor(x) end}
    450 debug.setmetatable(10, mt)
    451 assert(getmetatable(-2) == mt)
    452 assert((10)[3] == 13)
    453 assert((10)["3"] == 13)
    454 assert(#3.45 == 3)
    455 debug.setmetatable(23, nil)
    456 assert(getmetatable(-2) == nil)
    457 
    458 debug.setmetatable(true, mt)
    459 assert(getmetatable(false) == mt)
    460 mt.__index = function (a,b) return a or b end
    461 assert((true)[false] == true)
    462 assert((false)[false] == false)
    463 debug.setmetatable(false, nil)
    464 assert(getmetatable(true) == nil)
    465 
    466 debug.setmetatable(nil, mt)
    467 assert(getmetatable(nil) == mt)
    468 mt.__add = function (a,b) return (a or 1) + (b or 2) end
    469 assert(10 + nil == 12)
    470 assert(nil + 23 == 24)
    471 assert(nil + nil == 3)
    472 debug.setmetatable(nil, nil)
    473 assert(getmetatable(nil) == nil)
    474 
    475 debug.setmetatable(nil, {})
    476 
    477 
    478 -- loops in delegation
    479 a = {}; setmetatable(a, a); a.__index = a; a.__newindex = a
    480 assert(not pcall(function (a,b) return a[b] end, a, 10))
    481 assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true))
    482 
    483 -- bug in 5.1
    484 T, K, V = nil
    485 grandparent = {}
    486 grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end
    487 
    488 parent = {}
    489 parent.__newindex = parent
    490 setmetatable(parent, grandparent)
    491 
    492 child = setmetatable({}, parent)
    493 child.foo = 10      --> CRASH (on some machines)
    494 assert(T == parent and K == "foo" and V == 10)
    495 
    496 print 'OK'
    497 
    498 return 12
    499 
    500