github.com/jslyzt/glua@v0.0.0-20210819023911-4030c8e0234a/_lua5.1-tests/db.lua (about)

     1  -- testing debug library
     2  
     3  local function dostring(s) return assert(loadstring(s))() end
     4  
     5  print"testing debug library and debug information"
     6  
     7  do
     8  local a=1
     9  end
    10  
    11  function test (s, l, p)
    12    collectgarbage()   -- avoid gc during trace
    13    local function f (event, line)
    14      assert(event == 'line')
    15      local l = table.remove(l, 1)
    16      if p then print(l, line) end
    17      assert(l == line, "wrong trace!!")
    18    end
    19    debug.sethook(f,"l"); loadstring(s)(); debug.sethook()
    20    assert(table.getn(l) == 0)
    21  end
    22  
    23  
    24  do
    25    local a = debug.getinfo(print)
    26    assert(a.what == "C" and a.short_src == "[C]")
    27    local b = debug.getinfo(test, "SfL")
    28    assert(b.name == nil and b.what == "Lua" and b.linedefined == 11 and
    29           b.lastlinedefined == b.linedefined + 10 and
    30           b.func == test and not string.find(b.short_src, "%["))
    31    assert(b.activelines[b.linedefined + 1] and
    32           b.activelines[b.lastlinedefined])
    33    assert(not b.activelines[b.linedefined] and
    34           not b.activelines[b.lastlinedefined + 1])
    35  end
    36  
    37  
    38  -- test file and string names truncation
    39  a = "function f () end"
    40  local function dostring (s, x) return loadstring(s, x)() end
    41  dostring(a)
    42  assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
    43  dostring(a..string.format("; %s\n=1", string.rep('p', 400)))
    44  assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$'))
    45  dostring("\n"..a)
    46  assert(debug.getinfo(f).short_src == '[string "..."]')
    47  dostring(a, "")
    48  assert(debug.getinfo(f).short_src == '[string ""]')
    49  dostring(a, "@xuxu")
    50  assert(debug.getinfo(f).short_src == "xuxu")
    51  dostring(a, "@"..string.rep('p', 1000)..'t')
    52  assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$"))
    53  dostring(a, "=xuxu")
    54  assert(debug.getinfo(f).short_src == "xuxu")
    55  dostring(a, string.format("=%s", string.rep('x', 500)))
    56  assert(string.find(debug.getinfo(f).short_src, "^x*"))
    57  dostring(a, "=")
    58  assert(debug.getinfo(f).short_src == "")
    59  a = nil; f = nil;
    60  
    61  
    62  repeat
    63    local g = {x = function ()
    64      local a = debug.getinfo(2)
    65      assert(a.name == 'f' and a.namewhat == 'local')
    66      a = debug.getinfo(1)
    67      assert(a.name == 'x' and a.namewhat == 'field')
    68      return 'xixi'
    69    end}
    70    local f = function () return 1+1 and (not 1 or g.x()) end
    71    assert(f() == 'xixi')
    72    g = debug.getinfo(f)
    73    assert(g.what == "Lua" and g.func == f and g.namewhat == "" and not g.name)
    74  
    75    function f (x, name)   -- local!
    76      name = name or 'f'
    77      local a = debug.getinfo(1)
    78      assert(a.name == name and a.namewhat == 'local')
    79      return x
    80    end
    81  
    82    -- breaks in different conditions
    83    if 3>4 then break end; f()
    84    if 3<4 then a=1 else break end; f()
    85    while 1 do local x=10; break end; f()
    86    local b = 1
    87    if 3>4 then return math.sin(1) end; f()
    88    a = 3<4; f()
    89    a = 3<4 or 1; f()
    90    repeat local x=20; if 4>3 then f() else break end; f() until 1
    91    g = {}
    92    f(g).x = f(2) and f(10)+f(9)
    93    assert(g.x == f(19))
    94    function g(x) if not x then return 3 end return (x('a', 'x')) end
    95    assert(g(f) == 'a')
    96  until 1
    97  
    98  test([[if
    99  math.sin(1)
   100  then
   101    a=1
   102  else
   103    a=2
   104  end
   105  ]], {2,4,7})
   106  
   107  test([[--
   108  if nil then
   109    a=1
   110  else
   111    a=2
   112  end
   113  ]], {2,5,6})
   114  
   115  test([[a=1
   116  repeat
   117    a=a+1
   118  until a==3
   119  ]], {1,3,4,3,4})
   120  
   121  test([[ do
   122    return
   123  end
   124  ]], {2})
   125  
   126  test([[local a
   127  a=1
   128  while a<=3 do
   129    a=a+1
   130  end
   131  ]], {2,3,4,3,4,3,4,3,5})
   132  
   133  test([[while math.sin(1) do
   134    if math.sin(1)
   135    then
   136      break
   137    end
   138  end
   139  a=1]], {1,2,4,7})
   140  
   141  test([[for i=1,3 do
   142    a=i
   143  end
   144  ]], {1,2,1,2,1,2,1,3})
   145  
   146  test([[for i,v in pairs{'a','b'} do
   147    a=i..v
   148  end
   149  ]], {1,2,1,2,1,3})
   150  
   151  test([[for i=1,4 do a=1 end]], {1,1,1,1,1})
   152  
   153  
   154  
   155  print'+'
   156  
   157  a = {}; L = nil
   158  local glob = 1
   159  local oldglob = glob
   160  debug.sethook(function (e,l)
   161    collectgarbage()   -- force GC during a hook
   162    local f, m, c = debug.gethook()
   163    assert(m == 'crl' and c == 0)
   164    if e == "line" then
   165      if glob ~= oldglob then
   166        L = l-1   -- get the first line where "glob" has changed
   167        oldglob = glob
   168      end
   169    elseif e == "call" then
   170        local f = debug.getinfo(2, "f").func
   171        a[f] = 1
   172    else assert(e == "return")
   173    end
   174  end, "crl")
   175  
   176  function f(a,b)
   177    collectgarbage()
   178    local _, x = debug.getlocal(1, 1)
   179    local _, y = debug.getlocal(1, 2)
   180    assert(x == a and y == b)
   181    assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
   182    assert(debug.setlocal(2, 4, "maçã") == "B")
   183    x = debug.getinfo(2)
   184    assert(x.func == g and x.what == "Lua" and x.name == 'g' and
   185           x.nups == 0 and string.find(x.source, "^@.*db%.lua"))
   186    glob = glob+1
   187    assert(debug.getinfo(1, "l").currentline == L+1)
   188    assert(debug.getinfo(1, "l").currentline == L+2)
   189  end
   190  
   191  function foo()
   192    glob = glob+1
   193    assert(debug.getinfo(1, "l").currentline == L+1)
   194  end; foo()  -- set L
   195  -- check line counting inside strings and empty lines
   196  
   197  _ = 'alo\
   198  alo' .. [[
   199  
   200  ]]
   201  --[[
   202  ]]
   203  assert(debug.getinfo(1, "l").currentline == L+11)  -- check count of lines
   204  
   205  
   206  function g(...)
   207    do local a,b,c; a=math.sin(40); end
   208    local feijao
   209    local AAAA,B = "xuxu", "mamão"
   210    f(AAAA,B)
   211    assert(AAAA == "pera" and B == "maçã")
   212    do
   213       local B = 13
   214       local x,y = debug.getlocal(1,5)
   215       assert(x == 'B' and y == 13)
   216    end
   217  end
   218  
   219  g()
   220  
   221  
   222  assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print])
   223  
   224  
   225  -- tests for manipulating non-registered locals (C and Lua temporaries)
   226  
   227  local n, v = debug.getlocal(0, 1)
   228  assert(v == 0 and n == "(*temporary)")
   229  local n, v = debug.getlocal(0, 2)
   230  assert(v == 2 and n == "(*temporary)")
   231  assert(not debug.getlocal(0, 3))
   232  assert(not debug.getlocal(0, 0))
   233  
   234  function f()
   235    assert(select(2, debug.getlocal(2,3)) == 1)
   236    assert(not debug.getlocal(2,4))
   237    debug.setlocal(2, 3, 10)
   238    return 20
   239  end
   240  
   241  function g(a,b) return (a+1) + f() end
   242  
   243  assert(g(0,0) == 30)
   244   
   245  
   246  debug.sethook(nil);
   247  assert(debug.gethook() == nil)
   248  
   249  
   250  -- testing access to function arguments
   251  
   252  X = nil
   253  a = {}
   254  function a:f (a, b, ...) local c = 13 end
   255  debug.sethook(function (e)
   256    assert(e == "call")
   257    dostring("XX = 12")  -- test dostring inside hooks
   258    -- testing errors inside hooks
   259    assert(not pcall(loadstring("a='joao'+1")))
   260    debug.sethook(function (e, l) 
   261      assert(debug.getinfo(2, "l").currentline == l)
   262      local f,m,c = debug.gethook()
   263      assert(e == "line")
   264      assert(m == 'l' and c == 0)
   265      debug.sethook(nil)  -- hook is called only once
   266      assert(not X)       -- check that
   267      X = {}; local i = 1
   268      local x,y
   269      while 1 do
   270        x,y = debug.getlocal(2, i)
   271        if x==nil then break end
   272        X[x] = y
   273        i = i+1
   274      end
   275    end, "l")
   276  end, "c")
   277  
   278  a:f(1,2,3,4,5)
   279  assert(X.self == a and X.a == 1   and X.b == 2 and X.arg.n == 3 and X.c == nil)
   280  assert(XX == 12)
   281  assert(debug.gethook() == nil)
   282  
   283  
   284  -- testing upvalue access
   285  local function getupvalues (f)
   286    local t = {}
   287    local i = 1
   288    while true do
   289      local name, value = debug.getupvalue(f, i)
   290      if not name then break end
   291      assert(not t[name])
   292      t[name] = value
   293      i = i + 1
   294    end
   295    return t
   296  end
   297  
   298  local a,b,c = 1,2,3
   299  local function foo1 (a) b = a; return c end
   300  local function foo2 (x) a = x; return c+b end
   301  assert(debug.getupvalue(foo1, 3) == nil)
   302  assert(debug.getupvalue(foo1, 0) == nil)
   303  assert(debug.setupvalue(foo1, 3, "xuxu") == nil)
   304  local t = getupvalues(foo1)
   305  assert(t.a == nil and t.b == 2 and t.c == 3)
   306  t = getupvalues(foo2)
   307  assert(t.a == 1 and t.b == 2 and t.c == 3)
   308  assert(debug.setupvalue(foo1, 1, "xuxu") == "b")
   309  assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu")
   310  -- cannot manipulate C upvalues from Lua
   311  assert(debug.getupvalue(io.read, 1) == nil)  
   312  assert(debug.setupvalue(io.read, 1, 10) == nil)  
   313  
   314  
   315  -- testing count hooks
   316  local a=0
   317  debug.sethook(function (e) a=a+1 end, "", 1)
   318  a=0; for i=1,1000 do end; assert(1000 < a and a < 1012)
   319  debug.sethook(function (e) a=a+1 end, "", 4)
   320  a=0; for i=1,1000 do end; assert(250 < a and a < 255)
   321  local f,m,c = debug.gethook()
   322  assert(m == "" and c == 4)
   323  debug.sethook(function (e) a=a+1 end, "", 4000)
   324  a=0; for i=1,1000 do end; assert(a == 0)
   325  debug.sethook(print, "", 2^24 - 1)   -- count upperbound
   326  local f,m,c = debug.gethook()
   327  assert(({debug.gethook()})[3] == 2^24 - 1)
   328  debug.sethook()
   329  
   330  
   331  -- tests for tail calls
   332  local function f (x)
   333    if x then
   334      assert(debug.getinfo(1, "S").what == "Lua")
   335      local tail = debug.getinfo(2)
   336      assert(not pcall(getfenv, 3))
   337      assert(tail.what == "tail" and tail.short_src == "(tail call)" and
   338             tail.linedefined == -1 and tail.func == nil)
   339      assert(debug.getinfo(3, "f").func == g1)
   340      assert(getfenv(3))
   341      assert(debug.getinfo(4, "S").what == "tail")
   342      assert(not pcall(getfenv, 5))
   343      assert(debug.getinfo(5, "S").what == "main")
   344      assert(getfenv(5))
   345      print"+"
   346      end
   347  end
   348  
   349  function g(x) return f(x) end
   350  
   351  function g1(x) g(x) end
   352  
   353  local function h (x) local f=g1; return f(x) end
   354  
   355  h(true)
   356  
   357  local b = {}
   358  debug.sethook(function (e) table.insert(b, e) end, "cr")
   359  h(false)
   360  debug.sethook()
   361  local res = {"return",   -- first return (from sethook)
   362    "call", "call", "call", "call",
   363    "return", "tail return", "return", "tail return",
   364    "call",    -- last call (to sethook)
   365  }
   366  for _, k in ipairs(res) do assert(k == table.remove(b, 1)) end
   367  
   368  
   369  lim = 30000
   370  local function foo (x)
   371    if x==0 then
   372      assert(debug.getinfo(lim+2).what == "main")
   373      for i=2,lim do assert(debug.getinfo(i, "S").what == "tail") end
   374    else return foo(x-1)
   375    end
   376  end
   377  
   378  foo(lim)
   379  
   380  
   381  print"+"
   382  
   383  
   384  -- testing traceback
   385  
   386  assert(debug.traceback(print) == print)
   387  assert(debug.traceback(print, 4) == print)
   388  assert(string.find(debug.traceback("hi", 4), "^hi\n"))
   389  assert(string.find(debug.traceback("hi"), "^hi\n"))
   390  assert(not string.find(debug.traceback("hi"), "'traceback'"))
   391  assert(string.find(debug.traceback("hi", 0), "'traceback'"))
   392  assert(string.find(debug.traceback(), "^stack traceback:\n"))
   393  
   394  -- testing debugging of coroutines
   395  
   396  local function checktraceback (co, p)
   397    local tb = debug.traceback(co)
   398    local i = 0
   399    for l in string.gmatch(tb, "[^\n]+\n?") do
   400      assert(i == 0 or string.find(l, p[i]))
   401      i = i+1
   402    end
   403    assert(p[i] == nil)
   404  end
   405  
   406  
   407  local function f (n)
   408    if n > 0 then return f(n-1)
   409    else coroutine.yield() end
   410  end
   411  
   412  local co = coroutine.create(f)
   413  coroutine.resume(co, 3)
   414  checktraceback(co, {"yield", "db.lua", "tail", "tail", "tail"})
   415  
   416  
   417  co = coroutine.create(function (x)
   418         local a = 1
   419         coroutine.yield(debug.getinfo(1, "l"))
   420         coroutine.yield(debug.getinfo(1, "l").currentline)
   421         return a
   422       end)
   423  
   424  local tr = {}
   425  local foo = function (e, l) table.insert(tr, l) end
   426  debug.sethook(co, foo, "l")
   427  
   428  local _, l = coroutine.resume(co, 10)
   429  local x = debug.getinfo(co, 1, "lfLS")
   430  assert(x.currentline == l.currentline and x.activelines[x.currentline])
   431  assert(type(x.func) == "function")
   432  for i=x.linedefined + 1, x.lastlinedefined do
   433    assert(x.activelines[i])
   434    x.activelines[i] = nil
   435  end
   436  assert(next(x.activelines) == nil)   -- no 'extra' elements
   437  assert(debug.getinfo(co, 2) == nil)
   438  local a,b = debug.getlocal(co, 1, 1)
   439  assert(a == "x" and b == 10)
   440  a,b = debug.getlocal(co, 1, 2)
   441  assert(a == "a" and b == 1)
   442  debug.setlocal(co, 1, 2, "hi")
   443  assert(debug.gethook(co) == foo)
   444  assert(table.getn(tr) == 2 and
   445         tr[1] == l.currentline-1 and tr[2] == l.currentline)
   446  
   447  a,b,c = pcall(coroutine.resume, co)
   448  assert(a and b and c == l.currentline+1)
   449  checktraceback(co, {"yield", "in function <"})
   450  
   451  a,b = coroutine.resume(co)
   452  assert(a and b == "hi")
   453  assert(table.getn(tr) == 4 and tr[4] == l.currentline+2)
   454  assert(debug.gethook(co) == foo)
   455  assert(debug.gethook() == nil)
   456  checktraceback(co, {})
   457  
   458  
   459  -- check traceback of suspended (or dead with error) coroutines
   460  
   461  function f(i) if i==0 then error(i) else coroutine.yield(); f(i-1) end end
   462  
   463  co = coroutine.create(function (x) f(x) end)
   464  a, b = coroutine.resume(co, 3)
   465  t = {"'yield'", "'f'", "in function <"}
   466  while coroutine.status(co) == "suspended" do
   467    checktraceback(co, t)
   468    a, b = coroutine.resume(co)
   469    table.insert(t, 2, "'f'")   -- one more recursive call to 'f'
   470  end
   471  t[1] = "'error'"
   472  checktraceback(co, t)
   473  
   474  
   475  -- test acessing line numbers of a coroutine from a resume inside
   476  -- a C function (this is a known bug in Lua 5.0)
   477  
   478  local function g(x)
   479      coroutine.yield(x)
   480  end
   481  
   482  local function f (i)
   483    debug.sethook(function () end, "l")
   484    for j=1,1000 do
   485      g(i+j)
   486    end
   487  end
   488  
   489  local co = coroutine.wrap(f)
   490  co(10)
   491  pcall(co)
   492  pcall(co)
   493  
   494  
   495  assert(type(debug.getregistry()) == "table")
   496  
   497  
   498  print"OK"
   499