lua

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

db.lua (26280B)


      1 -- $Id: testes/db.lua $
      2 -- See Copyright Notice in file all.lua
      3 
      4 -- testing debug library
      5 
      6 local debug = require "debug"
      7 
      8 local function dostring(s) return assert(load(s))() end
      9 
     10 print"testing debug library and debug information"
     11 
     12 do
     13 local a=1
     14 end
     15 
     16 assert(not debug.gethook())
     17 
     18 local testline = 19         -- line where 'test' is defined
     19 local function test (s, l, p)     -- this must be line 19
     20   collectgarbage()   -- avoid gc during trace
     21   local function f (event, line)
     22     assert(event == 'line')
     23     local l = table.remove(l, 1)
     24     if p then print(l, line) end
     25     assert(l == line, "wrong trace!!")
     26   end
     27   debug.sethook(f,"l"); load(s)(); debug.sethook()
     28   assert(#l == 0)
     29 end
     30 
     31 
     32 do
     33   assert(not pcall(debug.getinfo, print, "X"))   -- invalid option
     34   assert(not pcall(debug.getinfo, 0, ">"))   -- invalid option
     35   assert(not debug.getinfo(1000))   -- out of range level
     36   assert(not debug.getinfo(-1))     -- out of range level
     37   local a = debug.getinfo(print)
     38   assert(a.what == "C" and a.short_src == "[C]")
     39   a = debug.getinfo(print, "L")
     40   assert(a.activelines == nil)
     41   local b = debug.getinfo(test, "SfL")
     42   assert(b.name == nil and b.what == "Lua" and b.linedefined == testline and
     43          b.lastlinedefined == b.linedefined + 10 and
     44          b.func == test and not string.find(b.short_src, "%["))
     45   assert(b.activelines[b.linedefined + 1] and
     46          b.activelines[b.lastlinedefined])
     47   assert(not b.activelines[b.linedefined] and
     48          not b.activelines[b.lastlinedefined + 1])
     49 end
     50 
     51 
     52 --  bug in 5.4.4-5.4.6: activelines in vararg functions
     53 --  without debug information
     54 do
     55   local func = load(string.dump(load("print(10)"), true))
     56   local actl = debug.getinfo(func, "L").activelines
     57   assert(#actl == 0)   -- no line info
     58 end
     59 
     60 
     61 -- test file and string names truncation
     62 local a = "function f () end"
     63 local function dostring (s, x) return load(s, x)() end
     64 dostring(a)
     65 assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
     66 dostring(a..string.format("; %s\n=1", string.rep('p', 400)))
     67 assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$'))
     68 dostring(a..string.format("; %s=1", string.rep('p', 400)))
     69 assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$'))
     70 dostring("\n"..a)
     71 assert(debug.getinfo(f).short_src == '[string "..."]')
     72 dostring(a, "")
     73 assert(debug.getinfo(f).short_src == '[string ""]')
     74 dostring(a, "@xuxu")
     75 assert(debug.getinfo(f).short_src == "xuxu")
     76 dostring(a, "@"..string.rep('p', 1000)..'t')
     77 assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$"))
     78 dostring(a, "=xuxu")
     79 assert(debug.getinfo(f).short_src == "xuxu")
     80 dostring(a, string.format("=%s", string.rep('x', 500)))
     81 assert(string.find(debug.getinfo(f).short_src, "^x*$"))
     82 dostring(a, "=")
     83 assert(debug.getinfo(f).short_src == "")
     84 _G.a = nil; _G.f = nil;
     85 _G[string.rep("p", 400)] = nil
     86 
     87 
     88 repeat
     89   local g = {x = function ()
     90     local a = debug.getinfo(2)
     91     assert(a.name == 'f' and a.namewhat == 'local')
     92     a = debug.getinfo(1)
     93     assert(a.name == 'x' and a.namewhat == 'field')
     94     return 'xixi'
     95   end}
     96   local f = function () return 1+1 and (not 1 or g.x()) end
     97   assert(f() == 'xixi')
     98   g = debug.getinfo(f)
     99   assert(g.what == "Lua" and g.func == f and g.namewhat == "" and not g.name)
    100 
    101   function f (x, name)   -- local!
    102     name = name or 'f'
    103     local a = debug.getinfo(1)
    104     assert(a.name == name and a.namewhat == 'local')
    105     return x
    106   end
    107 
    108   -- breaks in different conditions
    109   if 3>4 then break end; f()
    110   if 3<4 then a=1 else break end; f()
    111   while 1 do local x=10; break end; f()
    112   local b = 1
    113   if 3>4 then return math.sin(1) end; f()
    114   a = 3<4; f()
    115   a = 3<4 or 1; f()
    116   repeat local x=20; if 4>3 then f() else break end; f() until 1
    117   g = {}
    118   f(g).x = f(2) and f(10)+f(9)
    119   assert(g.x == f(19))
    120   function g(x) if not x then return 3 end return (x('a', 'x')) end
    121   assert(g(f) == 'a')
    122 until 1
    123 
    124 test([[if
    125 math.sin(1)
    126 then
    127   a=1
    128 else
    129   a=2
    130 end
    131 ]], {2,4,7})
    132 
    133 
    134 test([[
    135 local function foo()
    136 end
    137 foo()
    138 A = 1
    139 A = 2
    140 A = 3
    141 ]], {2, 3, 2, 4, 5, 6})
    142 _G.A = nil
    143 
    144 
    145 test([[--
    146 if nil then
    147   a=1
    148 else
    149   a=2
    150 end
    151 ]], {2,5,6})
    152 
    153 test([[a=1
    154 repeat
    155   a=a+1
    156 until a==3
    157 ]], {1,3,4,3,4})
    158 
    159 test([[ do
    160   return
    161 end
    162 ]], {2})
    163 
    164 test([[local a
    165 a=1
    166 while a<=3 do
    167   a=a+1
    168 end
    169 ]], {1,2,3,4,3,4,3,4,3,5})
    170 
    171 test([[while math.sin(1) do
    172   if math.sin(1)
    173   then break
    174   end
    175 end
    176 a=1]], {1,2,3,6})
    177 
    178 test([[for i=1,3 do
    179   a=i
    180 end
    181 ]], {1,2,1,2,1,2,1,3})
    182 
    183 test([[for i,v in pairs{'a','b'} do
    184   a=tostring(i) .. v
    185 end
    186 ]], {1,2,1,2,1,3})
    187 
    188 test([[for i=1,4 do a=1 end]], {1,1,1,1})
    189 
    190 _G.a = nil
    191 
    192 
    193 do   -- testing line info/trace with large gaps in source
    194 
    195   local a = {1, 2, 3, 10, 124, 125, 126, 127, 128, 129, 130,
    196              255, 256, 257, 500, 1000}
    197   local s = [[
    198      local b = {10}
    199      a = b[1] X + Y b[1]
    200      b = 4
    201   ]]
    202   for _, i in ipairs(a) do
    203     local subs = {X = string.rep("\n", i)}
    204     for _, j in ipairs(a) do
    205       subs.Y = string.rep("\n", j)
    206       local s = string.gsub(s, "[XY]", subs)
    207       test(s, {1, 2 + i, 2 + i + j, 2 + i, 2 + i + j, 3 + i + j})
    208     end
    209   end
    210 end
    211 _G.a = nil
    212 
    213 
    214 do   -- testing active lines
    215   local function checkactivelines (f, lines)
    216     local t = debug.getinfo(f, "SL")
    217     for _, l in pairs(lines) do
    218       l = l + t.linedefined
    219       assert(t.activelines[l])
    220       t.activelines[l] = undef
    221     end
    222     assert(next(t.activelines) == nil)   -- no extra lines
    223   end
    224 
    225   checkactivelines(function (...)   -- vararg function
    226     -- 1st line is empty
    227     -- 2nd line is empty
    228     -- 3th line is empty
    229     local a = 20
    230     -- 5th line is empty
    231     local b = 30
    232     -- 7th line is empty
    233   end, {4, 6, 8})
    234 
    235   checkactivelines(function (a)
    236     -- 1st line is empty
    237     -- 2nd line is empty
    238     local a = 20
    239     local b = 30
    240     -- 5th line is empty
    241   end, {3, 4, 6})
    242 
    243   checkactivelines(function (a, b, ...) end, {0})
    244 
    245   checkactivelines(function (a, b)
    246   end, {1})
    247 
    248   for _, n in pairs{0, 1, 2, 10, 50, 100, 1000, 10000} do
    249     checkactivelines(
    250       load(string.format("%s return 1", string.rep("\n", n))),
    251       {n + 1})
    252   end
    253 
    254 end
    255 
    256 print'+'
    257 
    258 -- invalid levels in [gs]etlocal
    259 assert(not pcall(debug.getlocal, 20, 1))
    260 assert(not pcall(debug.setlocal, -1, 1, 10))
    261 
    262 
    263 -- parameter names
    264 local function foo (a,b,...) local d, e end
    265 local co = coroutine.create(foo)
    266 
    267 assert(debug.getlocal(foo, 1) == 'a')
    268 assert(debug.getlocal(foo, 2) == 'b')
    269 assert(not debug.getlocal(foo, 3))
    270 assert(debug.getlocal(co, foo, 1) == 'a')
    271 assert(debug.getlocal(co, foo, 2) == 'b')
    272 assert(not debug.getlocal(co, foo, 3))
    273 
    274 assert(not debug.getlocal(print, 1))
    275 
    276 
    277 local function foo () return (debug.getlocal(1, -1)) end
    278 assert(not foo(10))
    279 
    280 
    281 -- varargs
    282 local function foo (a, ...)
    283   local t = table.pack(...)
    284   for i = 1, t.n do
    285     local n, v = debug.getlocal(1, -i)
    286     assert(n == "(vararg)" and v == t[i])
    287   end
    288   assert(not debug.getlocal(1, -(t.n + 1)))
    289   assert(not debug.setlocal(1, -(t.n + 1), 30))
    290   if t.n > 0 then
    291     (function (x)
    292       assert(debug.setlocal(2, -1, x) == "(vararg)")
    293       assert(debug.setlocal(2, -t.n, x) == "(vararg)")
    294      end)(430)
    295      assert(... == 430)
    296   end
    297 end
    298 
    299 foo()
    300 foo(print)
    301 foo(200, 3, 4)
    302 local a = {}
    303 for i = 1, (_soft and 100 or 1000) do a[i] = i end
    304 foo(table.unpack(a))
    305 
    306 
    307 
    308 do   -- test hook presence in debug info
    309   assert(not debug.gethook())
    310   local count = 0
    311   local function f ()
    312     assert(debug.getinfo(1).namewhat == "hook")
    313     local sndline = string.match(debug.traceback(), "\n(.-)\n")
    314     assert(string.find(sndline, "hook"))
    315     count = count + 1
    316   end
    317   debug.sethook(f, "l")
    318   local a = 0
    319   _ENV.a = a
    320   a = 1
    321   debug.sethook()
    322   assert(count == 4)
    323 end
    324 _ENV.a = nil
    325 
    326 
    327 -- hook table has weak keys
    328 assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k')
    329 
    330 
    331 a = {}; local L = nil
    332 local glob = 1
    333 local oldglob = glob
    334 debug.sethook(function (e,l)
    335   collectgarbage()   -- force GC during a hook
    336   local f, m, c = debug.gethook()
    337   assert(m == 'crl' and c == 0)
    338   if e == "line" then
    339     if glob ~= oldglob then
    340       L = l-1   -- get the first line where "glob" has changed
    341       oldglob = glob
    342     end
    343   elseif e == "call" then
    344       local f = debug.getinfo(2, "f").func
    345       a[f] = 1
    346   else assert(e == "return")
    347   end
    348 end, "crl")
    349 
    350 
    351 function f(a,b)
    352   collectgarbage()
    353   local _, x = debug.getlocal(1, 1)
    354   local _, y = debug.getlocal(1, 2)
    355   assert(x == a and y == b)
    356   assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
    357   assert(debug.setlocal(2, 4, "manga") == "B")
    358   x = debug.getinfo(2)
    359   assert(x.func == g and x.what == "Lua" and x.name == 'g' and
    360          x.nups == 2 and string.find(x.source, "^@.*db%.lua$"))
    361   glob = glob+1
    362   assert(debug.getinfo(1, "l").currentline == L+1)
    363   assert(debug.getinfo(1, "l").currentline == L+2)
    364 end
    365 
    366 function foo()
    367   glob = glob+1
    368   assert(debug.getinfo(1, "l").currentline == L+1)
    369 end; foo()  -- set L
    370 -- check line counting inside strings and empty lines
    371 
    372 local _ = 'alo\
    373 alo' .. [[
    374 
    375 ]]
    376 --[[
    377 ]]
    378 assert(debug.getinfo(1, "l").currentline == L+11)  -- check count of lines
    379 
    380 
    381 function g (...)
    382   local arg = {...}
    383   do local a,b,c; a=math.sin(40); end
    384   local feijao
    385   local AAAA,B = "xuxu", "abacate"
    386   f(AAAA,B)
    387   assert(AAAA == "pera" and B == "manga")
    388   do
    389      local B = 13
    390      local x,y = debug.getlocal(1,5)
    391      assert(x == 'B' and y == 13)
    392   end
    393 end
    394 
    395 g()
    396 
    397 
    398 assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print])
    399 
    400 
    401 -- tests for manipulating non-registered locals (C and Lua temporaries)
    402 
    403 local n, v = debug.getlocal(0, 1)
    404 assert(v == 0 and n == "(C temporary)")
    405 local n, v = debug.getlocal(0, 2)
    406 assert(v == 2 and n == "(C temporary)")
    407 assert(not debug.getlocal(0, 3))
    408 assert(not debug.getlocal(0, 0))
    409 
    410 function f()
    411   assert(select(2, debug.getlocal(2,3)) == 1)
    412   assert(not debug.getlocal(2,4))
    413   debug.setlocal(2, 3, 10)
    414   return 20
    415 end
    416 
    417 function g(a,b) return (a+1) + f() end
    418 
    419 assert(g(0,0) == 30)
    420  
    421 _G.f, _G.g = nil
    422 
    423 debug.sethook(nil);
    424 assert(not debug.gethook())
    425 
    426 
    427 -- minimal tests for setuservalue/getuservalue
    428 do
    429   assert(not debug.setuservalue(io.stdin, 10))
    430   local a, b = debug.getuservalue(io.stdin, 10)
    431   assert(a == nil and not b)
    432 end
    433 
    434 -- testing iteraction between multiple values x hooks
    435 do
    436   local function f(...) return 3, ... end
    437   local count = 0
    438   local a = {}
    439   for i = 1, 100 do a[i] = i end
    440   debug.sethook(function () count = count + 1 end, "", 1)
    441   local t = {table.unpack(a)}
    442   assert(#t == 100)
    443   t = {table.unpack(a, 1, 3)}
    444   assert(#t == 3)
    445   t = {f(table.unpack(a, 1, 30))}
    446   assert(#t == 31)
    447 end
    448 
    449 
    450 -- testing access to function arguments
    451 
    452 local function collectlocals (level)
    453   local tab = {}
    454   for i = 1, math.huge do
    455     local n, v = debug.getlocal(level + 1, i)
    456     if not (n and string.find(n, "^[a-zA-Z0-9_]+$")) then
    457        break   -- consider only real variables
    458     end
    459     tab[n] = v
    460   end
    461   return tab
    462 end
    463 
    464 
    465 local X = nil
    466 a = {}
    467 function a:f (a, b, ...) local arg = {...}; local c = 13 end
    468 debug.sethook(function (e)
    469   assert(e == "call")
    470   dostring("XX = 12")  -- test dostring inside hooks
    471   -- testing errors inside hooks
    472   assert(not pcall(load("a='joao'+1")))
    473   debug.sethook(function (e, l) 
    474     assert(debug.getinfo(2, "l").currentline == l)
    475     local f,m,c = debug.gethook()
    476     assert(e == "line")
    477     assert(m == 'l' and c == 0)
    478     debug.sethook(nil)  -- hook is called only once
    479     assert(not X)       -- check that
    480     X = collectlocals(2)
    481   end, "l")
    482 end, "c")
    483 
    484 a:f(1,2,3,4,5)
    485 assert(X.self == a and X.a == 1   and X.b == 2 and X.c == nil)
    486 assert(XX == 12)
    487 assert(not debug.gethook())
    488 _G.XX = nil
    489 
    490 
    491 -- testing access to local variables in return hook (bug in 5.2)
    492 do
    493   local X = false
    494 
    495   local function foo (a, b, ...)
    496     do local x,y,z end
    497     local c, d = 10, 20
    498     return
    499   end
    500 
    501   local function aux ()
    502     if debug.getinfo(2).name == "foo" then
    503       X = true   -- to signal that it found 'foo'
    504       local tab = {a = 100, b = 200, c = 10, d = 20}
    505       for n, v in pairs(collectlocals(2)) do
    506         assert(tab[n] == v)
    507         tab[n] = undef
    508       end
    509       assert(next(tab) == nil)    -- 'tab' must be empty
    510     end
    511   end
    512 
    513   debug.sethook(aux, "r"); foo(100, 200); debug.sethook()
    514   assert(X)
    515 
    516 end
    517 
    518 
    519 local function eqseq (t1, t2)
    520   assert(#t1 == #t2)
    521   for i = 1, #t1 do
    522     assert(t1[i] == t2[i])
    523   end
    524 end
    525 
    526 
    527 do  print("testing inspection of parameters/returned values")
    528   local on = false
    529   local inp, out
    530 
    531   local function hook (event)
    532     if not on then return end
    533     local ar = debug.getinfo(2, "ruS")
    534     local t = {}
    535     for i = ar.ftransfer, ar.ftransfer + ar.ntransfer - 1 do
    536       local _, v = debug.getlocal(2, i)
    537       t[#t + 1] = v 
    538     end
    539     if event == "return" then
    540       out = t
    541     else
    542       inp = t
    543     end
    544   end
    545 
    546   debug.sethook(hook, "cr")
    547 
    548   on = true; math.sin(3); on = false
    549   eqseq(inp, {3}); eqseq(out, {math.sin(3)})
    550 
    551   on = true; select(2, 10, 20, 30, 40); on = false
    552   eqseq(inp, {2, 10, 20, 30, 40}); eqseq(out, {20, 30, 40})
    553 
    554   local function foo (a, ...) return ... end
    555   local function foo1 () on = not on; return foo(20, 10, 0) end
    556   foo1(); on = false
    557   eqseq(inp, {20}); eqseq(out, {10, 0})
    558 
    559   debug.sethook()
    560 end
    561 
    562 
    563 
    564 -- testing upvalue access
    565 local function getupvalues (f)
    566   local t = {}
    567   local i = 1
    568   while true do
    569     local name, value = debug.getupvalue(f, i)
    570     if not name then break end
    571     assert(not t[name])
    572     t[name] = value
    573     i = i + 1
    574   end
    575   return t
    576 end
    577 
    578 local a,b,c = 1,2,3
    579 local function foo1 (a) b = a; return c end
    580 local function foo2 (x) a = x; return c+b end
    581 assert(not debug.getupvalue(foo1, 3))
    582 assert(not debug.getupvalue(foo1, 0))
    583 assert(not debug.setupvalue(foo1, 3, "xuxu"))
    584 local t = getupvalues(foo1)
    585 assert(t.a == nil and t.b == 2 and t.c == 3)
    586 t = getupvalues(foo2)
    587 assert(t.a == 1 and t.b == 2 and t.c == 3)
    588 assert(debug.setupvalue(foo1, 1, "xuxu") == "b")
    589 assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu")
    590 -- upvalues of C functions are allways "called" "" (the empty string)
    591 assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "")  
    592 
    593 
    594 -- testing count hooks
    595 local a=0
    596 debug.sethook(function (e) a=a+1 end, "", 1)
    597 a=0; for i=1,1000 do end; assert(1000 < a and a < 1012)
    598 debug.sethook(function (e) a=a+1 end, "", 4)
    599 a=0; for i=1,1000 do end; assert(250 < a and a < 255)
    600 local f,m,c = debug.gethook()
    601 assert(m == "" and c == 4)
    602 debug.sethook(function (e) a=a+1 end, "", 4000)
    603 a=0; for i=1,1000 do end; assert(a == 0)
    604 
    605 do
    606   debug.sethook(print, "", 2^24 - 1)   -- count upperbound
    607   local f,m,c = debug.gethook()
    608   assert(({debug.gethook()})[3] == 2^24 - 1)
    609 end
    610 
    611 debug.sethook()
    612 
    613 local g, g1
    614 
    615 -- tests for tail calls
    616 local function f (x)
    617   if x then
    618     assert(debug.getinfo(1, "S").what == "Lua")
    619     assert(debug.getinfo(1, "t").istailcall == true)
    620     local tail = debug.getinfo(2)
    621     assert(tail.func == g1 and tail.istailcall == true)
    622     assert(debug.getinfo(3, "S").what == "main")
    623     print"+"
    624     end
    625 end
    626 
    627 assert(debug.getinfo(print, 't').istailcall == false)
    628 assert(debug.getinfo(print, 't').extraargs == 0)
    629 
    630 function g(x) return f(x) end
    631 
    632 function g1(x) g(x) end
    633 
    634 local function h (x) local f=g1; return f(x) end
    635 
    636 h(true)
    637 
    638 local b = {}
    639 debug.sethook(function (e) table.insert(b, e) end, "cr")
    640 h(false)
    641 debug.sethook()
    642 local res = {"return",   -- first return (from sethook)
    643   "call", "tail call", "call", "tail call",
    644   "return", "return",
    645   "call",    -- last call (to sethook)
    646 }
    647 for i = 1, #res do assert(res[i] == table.remove(b, 1)) end
    648 
    649 b = 0
    650 debug.sethook(function (e)
    651                 if e == "tail call" then
    652                   b = b + 1
    653                   assert(debug.getinfo(2, "t").istailcall == true)
    654                 else
    655                   assert(debug.getinfo(2, "t").istailcall == false)
    656                 end
    657               end, "c")
    658 h(false)
    659 debug.sethook()
    660 assert(b == 2)   -- two tail calls
    661 
    662 local lim = _soft and 3000 or 30000
    663 local function foo (x)
    664   if x==0 then
    665     assert(debug.getinfo(2).what == "main")
    666     local info = debug.getinfo(1)
    667     assert(info.istailcall == true and info.func == foo)
    668   else return foo(x-1)
    669   end
    670 end
    671 
    672 foo(lim)
    673 
    674 
    675 print"+"
    676 
    677 
    678 -- testing local function information
    679 co = load[[
    680   local A = function ()
    681     return x
    682   end
    683   return
    684 ]]
    685 
    686 local a = 0
    687 -- 'A' should be visible to debugger only after its complete definition
    688 debug.sethook(function (e, l)
    689   if l == 3 then a = a + 1; assert(debug.getlocal(2, 1) == "(temporary)")
    690   elseif l == 4 then a = a + 1; assert(debug.getlocal(2, 1) == "A")
    691   end
    692 end, "l")
    693 co()  -- run local function definition
    694 debug.sethook()  -- turn off hook
    695 assert(a == 2)   -- ensure all two lines where hooked
    696 
    697 -- testing traceback
    698 
    699 assert(debug.traceback(print) == print)
    700 assert(debug.traceback(print, 4) == print)
    701 assert(string.find(debug.traceback("hi", 4), "^hi\n"))
    702 assert(string.find(debug.traceback("hi"), "^hi\n"))
    703 assert(not string.find(debug.traceback("hi"), "'debug.traceback'"))
    704 assert(string.find(debug.traceback("hi", 0), "'debug.traceback'"))
    705 assert(string.find(debug.traceback(), "^stack traceback:\n"))
    706 
    707 do  -- C-function names in traceback
    708   local st, msg = (function () return pcall end)()(debug.traceback)
    709   assert(st == true and string.find(msg, "pcall"))
    710 end
    711 
    712 
    713 -- testing nparams, nups e isvararg
    714 local t = debug.getinfo(print, "u")
    715 assert(t.isvararg == true and t.nparams == 0 and t.nups == 0)
    716 
    717 t = debug.getinfo(function (a,b,c) end, "u")
    718 assert(t.isvararg == false and t.nparams == 3 and t.nups == 0)
    719 
    720 t = debug.getinfo(function (a,b,...) return t[a] end, "u")
    721 assert(t.isvararg == true and t.nparams == 2 and t.nups == 1)
    722 
    723 t = debug.getinfo(1)   -- main
    724 assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and
    725        debug.getupvalue(t.func, 1) == "_ENV")
    726 
    727 t = debug.getinfo(math.sin)   -- C function
    728 assert(t.isvararg == true and t.nparams == 0 and t.nups == 0)
    729 
    730 t = debug.getinfo(string.gmatch("abc", "a"))   -- C closure
    731 assert(t.isvararg == true and t.nparams == 0 and t.nups > 0)
    732 
    733 
    734 
    735 -- testing debugging of coroutines
    736 
    737 local function checktraceback (co, p, level)
    738   local tb = debug.traceback(co, nil, level)
    739   local i = 0
    740   for l in string.gmatch(tb, "[^\n]+\n?") do
    741     assert(i == 0 or string.find(l, p[i]))
    742     i = i+1
    743   end
    744   assert(p[i] == undef)
    745 end
    746 
    747 
    748 local function f (n)
    749   if n > 0 then f(n-1)
    750   else coroutine.yield() end
    751 end
    752 
    753 local co = coroutine.create(f)
    754 coroutine.resume(co, 3)
    755 checktraceback(co, {"yield", "db.lua", "db.lua", "db.lua", "db.lua"})
    756 checktraceback(co, {"db.lua", "db.lua", "db.lua", "db.lua"}, 1)
    757 checktraceback(co, {"db.lua", "db.lua", "db.lua"}, 2)
    758 checktraceback(co, {"db.lua"}, 4)
    759 checktraceback(co, {}, 40)
    760 
    761 
    762 co = coroutine.create(function (x)
    763        local a = 1
    764        coroutine.yield(debug.getinfo(1, "l"))
    765        coroutine.yield(debug.getinfo(1, "l").currentline)
    766        return a
    767      end)
    768 
    769 local tr = {}
    770 local foo = function (e, l) if l then table.insert(tr, l) end end
    771 debug.sethook(co, foo, "lcr")
    772 
    773 local _, l = coroutine.resume(co, 10)
    774 local x = debug.getinfo(co, 1, "lfLS")
    775 assert(x.currentline == l.currentline and x.activelines[x.currentline])
    776 assert(type(x.func) == "function")
    777 for i=x.linedefined + 1, x.lastlinedefined do
    778   assert(x.activelines[i])
    779   x.activelines[i] = undef
    780 end
    781 assert(next(x.activelines) == nil)   -- no 'extra' elements
    782 assert(not debug.getinfo(co, 2))
    783 local a,b = debug.getlocal(co, 1, 1)
    784 assert(a == "x" and b == 10)
    785 a,b = debug.getlocal(co, 1, 2)
    786 assert(a == "a" and b == 1)
    787 debug.setlocal(co, 1, 2, "hi")
    788 assert(debug.gethook(co) == foo)
    789 assert(#tr == 2 and
    790        tr[1] == l.currentline-1 and tr[2] == l.currentline)
    791 
    792 a,b,c = pcall(coroutine.resume, co)
    793 assert(a and b and c == l.currentline+1)
    794 checktraceback(co, {"yield", "in function <"})
    795 
    796 a,b = coroutine.resume(co)
    797 assert(a and b == "hi")
    798 assert(#tr == 4 and tr[4] == l.currentline+2)
    799 assert(debug.gethook(co) == foo)
    800 assert(not debug.gethook())
    801 checktraceback(co, {})
    802 
    803 
    804 -- check get/setlocal in coroutines
    805 co = coroutine.create(function (x)
    806   local a, b = coroutine.yield(x)
    807   assert(a == 100 and b == nil)
    808   return x
    809 end)
    810 a, b = coroutine.resume(co, 10)
    811 assert(a and b == 10)
    812 a, b = debug.getlocal(co, 1, 1)
    813 assert(a == "x" and b == 10)
    814 assert(not debug.getlocal(co, 1, 5))
    815 assert(debug.setlocal(co, 1, 1, 30) == "x")
    816 assert(not debug.setlocal(co, 1, 5, 40))
    817 a, b = coroutine.resume(co, 100)
    818 assert(a and b == 30)
    819 
    820 
    821 -- check traceback of suspended (or dead with error) coroutines
    822 
    823 function f(i)
    824   if i == 0 then error(i)
    825   else coroutine.yield(); f(i-1)
    826   end
    827 end
    828 
    829 
    830 co = coroutine.create(function (x) f(x) end)
    831 a, b = coroutine.resume(co, 3)
    832 t = {"'coroutine.yield'", "'f'", "in function <"}
    833 while coroutine.status(co) == "suspended" do
    834   checktraceback(co, t)
    835   a, b = coroutine.resume(co)
    836   table.insert(t, 2, "'f'")   -- one more recursive call to 'f'
    837 end
    838 t[1] = "'error'"
    839 checktraceback(co, t)
    840 
    841 
    842 -- test acessing line numbers of a coroutine from a resume inside
    843 -- a C function (this is a known bug in Lua 5.0)
    844 
    845 local function g(x)
    846     coroutine.yield(x)
    847 end
    848 
    849 local function f (i)
    850   debug.sethook(function () end, "l")
    851   for j=1,1000 do
    852     g(i+j)
    853   end
    854 end
    855 
    856 local co = coroutine.wrap(f)
    857 co(10)
    858 pcall(co)
    859 pcall(co)
    860 
    861 
    862 assert(type(debug.getregistry()) == "table")
    863 
    864 
    865 -- test tagmethod information
    866 local a = {}
    867 local function f (t)
    868   local info = debug.getinfo(1);
    869   assert(info.namewhat == "metamethod")
    870   a.op = info.name
    871   return info.name
    872 end
    873 setmetatable(a, {
    874   __index = f; __add = f; __div = f; __mod = f; __concat = f; __pow = f;
    875   __mul = f; __idiv = f; __unm = f; __len = f; __sub = f;
    876   __shl = f; __shr = f; __bor = f; __bxor = f;
    877   __eq = f; __le = f; __lt = f; __unm = f; __len = f; __band = f;
    878   __bnot = f;
    879 })
    880 
    881 local b = setmetatable({}, getmetatable(a))
    882 
    883 assert(a[3] == "index" and a^3 == "pow" and a..a == "concat")
    884 assert(a/3 == "div" and 3%a == "mod")
    885 assert(a+3 == "add" and 3-a == "sub" and a*3 == "mul" and
    886        -a == "unm" and #a == "len" and a&3 == "band")
    887 assert(a + 30000 == "add" and a - 3.0 == "sub" and a * 3.0 == "mul" and
    888        -a == "unm" and #a == "len" and a & 3 == "band")
    889 assert(a|3 == "bor" and 3~a == "bxor" and a<<3 == "shl" and a>>1 == "shr")
    890 assert (a==b and a.op == "eq")
    891 assert (a>=b and a.op == "le")
    892 assert ("x">=a and a.op == "le")
    893 assert (a>b and a.op == "lt")
    894 assert (a>10 and a.op == "lt")
    895 assert(~a == "bnot")
    896 
    897 do   -- testing for-iterator name
    898   local function f()
    899     assert(debug.getinfo(1).name == "for iterator")
    900   end
    901 
    902   for i in f do end
    903 end
    904 
    905 
    906 do   -- testing debug info for finalizers
    907   local name = nil
    908 
    909   -- create a piece of garbage with a finalizer
    910   setmetatable({}, {__gc = function ()
    911     local t = debug.getinfo(1)   -- get function information
    912     assert(t.namewhat == "metamethod")
    913     name = t.name
    914   end})
    915 
    916   -- repeat until previous finalizer runs (setting 'name')
    917   repeat local a = {} until name
    918   assert(name == "__gc")
    919 end
    920 
    921 
    922 do
    923   print("testing traceback sizes")
    924 
    925   local function countlines (s)
    926     return select(2, string.gsub(s, "\n", ""))
    927   end
    928 
    929   local function deep (lvl, n)
    930     if lvl == 0 then
    931       return (debug.traceback("message", n))
    932     else
    933       return (deep(lvl-1, n))
    934     end
    935   end
    936 
    937   local function checkdeep (total, start)
    938     local s = deep(total, start)
    939     local rest = string.match(s, "^message\nstack traceback:\n(.*)$")
    940     local cl = countlines(rest)
    941     -- at most 10 lines in first part, 11 in second, plus '...'
    942     assert(cl <= 10 + 11 + 1)
    943     local brk = string.find(rest, "%.%.%.\t%(skip")
    944     if brk then   -- does message have '...'?
    945       local rest1 = string.sub(rest, 1, brk)
    946       local rest2 = string.sub(rest, brk, #rest)
    947       assert(countlines(rest1) == 10 and countlines(rest2) == 11)
    948     else
    949       assert(cl == total - start + 2)
    950     end
    951   end
    952 
    953   for d = 1, 51, 10 do
    954     for l = 1, d do
    955       -- use coroutines to ensure complete control of the stack
    956       coroutine.wrap(checkdeep)(d, l)
    957     end
    958   end
    959 
    960 end
    961 
    962 
    963 print("testing debug functions on chunk without debug info")
    964 local prog = [[-- program to be loaded without debug information (strip)
    965 local debug = require'debug'
    966 local a = 12  -- a local variable
    967 
    968 local n, v = debug.getlocal(1, 1)
    969 assert(n == "(temporary)" and v == debug)   -- unkown name but known value
    970 n, v = debug.getlocal(1, 2)
    971 assert(n == "(temporary)" and v == 12)   -- unkown name but known value
    972 
    973 -- a function with an upvalue
    974 local f = function () local x; return a end
    975 n, v = debug.getupvalue(f, 1)
    976 assert(n == "(no name)" and v == 12)
    977 assert(debug.setupvalue(f, 1, 13) == "(no name)")
    978 assert(a == 13)
    979 
    980 local t = debug.getinfo(f)
    981 assert(t.name == nil and t.linedefined > 0 and
    982        t.lastlinedefined == t.linedefined and
    983        t.short_src == "?")
    984 assert(debug.getinfo(1).currentline == -1)
    985 
    986 t = debug.getinfo(f, "L").activelines
    987 assert(next(t) == nil)    -- active lines are empty
    988 
    989 -- dump/load a function without debug info
    990 f = load(string.dump(f))
    991 
    992 t = debug.getinfo(f)
    993 assert(t.name == nil and t.linedefined > 0 and
    994        t.lastlinedefined == t.linedefined and
    995        t.short_src == "?")
    996 assert(debug.getinfo(1).currentline == -1)
    997 
    998 return a
    999 ]]
   1000 
   1001 
   1002 -- load 'prog' without debug info
   1003 local f = assert(load(string.dump(load(prog), true)))
   1004 
   1005 assert(f() == 13)
   1006 
   1007 do   -- bug in 5.4.0: line hooks in stripped code
   1008   local function foo ()
   1009     local a = 1
   1010     local b = 2
   1011     return b
   1012   end
   1013 
   1014   local s = load(string.dump(foo, true))
   1015   local line = true
   1016   debug.sethook(function (e, l)
   1017     assert(e == "line")
   1018     line = l
   1019   end, "l")
   1020   assert(s() == 2); debug.sethook(nil)
   1021   assert(line == nil)  -- hook called withoug debug info for 1st instruction
   1022 end
   1023 
   1024 do   -- tests for 'source' in binary dumps
   1025   local prog = [[
   1026     return function (x)
   1027       return function (y) 
   1028         return x + y
   1029       end
   1030     end
   1031   ]]
   1032   local name = string.rep("x", 1000)
   1033   local p = assert(load(prog, name))
   1034   -- load 'p' as a binary chunk with debug information
   1035   local c = string.dump(p)
   1036   assert(#c > 1000 and #c < 2000)   -- no repetition of 'source' in dump
   1037   local f = assert(load(c))
   1038   local g = f()
   1039   local h = g(3)
   1040   assert(h(5) == 8)
   1041   assert(debug.getinfo(f).source == name and   -- all functions have 'source'
   1042          debug.getinfo(g).source == name and 
   1043          debug.getinfo(h).source == name)
   1044   -- again, without debug info
   1045   local c = string.dump(p, true)
   1046   assert(#c < 500)   -- no 'source' in dump
   1047   local f = assert(load(c))
   1048   local g = f()
   1049   local h = g(30)
   1050   assert(h(50) == 80)
   1051   assert(debug.getinfo(f).source == '=?' and   -- no function has 'source'
   1052          debug.getinfo(g).source == '=?' and 
   1053          debug.getinfo(h).source == '=?')
   1054 end
   1055 
   1056 print"OK"
   1057