1-- $Id: testes/db.lua $
   2-- See Copyright Notice in file all.lua
   3
   4-- testing debug library
   5
   6local debug = require "debug"
   7
   8local function dostring(s) return assert(load(s))() end
   9
  10print"testing debug library and debug information"
  11
  12do
  13local a=1
  14end
  15
  16assert(not debug.gethook())
  17
  18local testline = 19         -- line where 'test' is defined
  19local 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)
  29end
  30
  31
  32do
  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])
  49end
  50
  51
  52--  bug in 5.4.4-5.4.6: activelines in vararg functions
  53--  without debug information
  54do
  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
  58end
  59
  60
  61-- test file and string names truncation
  62local a = "function f () end"
  63local function dostring (s, x) return load(s, x)() end
  64dostring(a)
  65assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
  66dostring(a..string.format("; %s\n=1", string.rep('p', 400)))
  67assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$'))
  68dostring(a..string.format("; %s=1", string.rep('p', 400)))
  69assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$'))
  70dostring("\n"..a)
  71assert(debug.getinfo(f).short_src == '[string "..."]')
  72dostring(a, "")
  73assert(debug.getinfo(f).short_src == '[string ""]')
  74dostring(a, "@xuxu")
  75assert(debug.getinfo(f).short_src == "xuxu")
  76dostring(a, "@"..string.rep('p', 1000)..'t')
  77assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$"))
  78dostring(a, "=xuxu")
  79assert(debug.getinfo(f).short_src == "xuxu")
  80dostring(a, string.format("=%s", string.rep('x', 500)))
  81assert(string.find(debug.getinfo(f).short_src, "^x*$"))
  82dostring(a, "=")
  83assert(debug.getinfo(f).short_src == "")
  84_G.a = nil; _G.f = nil;
  85_G[string.rep("p", 400)] = nil
  86
  87
  88repeat
  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')
 122until 1
 123
 124test([[if
 125math.sin(1)
 126then
 127  a=1
 128else
 129  a=2
 130end
 131]], {2,3,4,7})
 132
 133
 134test([[
 135local function foo()
 136end
 137foo()
 138A = 1
 139A = 2
 140A = 3
 141]], {2, 3, 2, 4, 5, 6})
 142_G.A = nil
 143
 144
 145test([[--
 146if nil then
 147  a=1
 148else
 149  a=2
 150end
 151]], {2,5,6})
 152
 153test([[a=1
 154repeat
 155  a=a+1
 156until a==3
 157]], {1,3,4,3,4})
 158
 159test([[ do
 160  return
 161end
 162]], {2})
 163
 164test([[local a
 165a=1
 166while a<=3 do
 167  a=a+1
 168end
 169]], {1,2,3,4,3,4,3,4,3,5})
 170
 171test([[while math.sin(1) do
 172  if math.sin(1)
 173  then break
 174  end
 175end
 176a=1]], {1,2,3,6})
 177
 178test([[for i=1,3 do
 179  a=i
 180end
 181]], {1,2,1,2,1,2,1,3})
 182
 183test([[for i,v in pairs{'a','b'} do
 184  a=tostring(i) .. v
 185end
 186]], {1,2,1,2,1,3})
 187
 188test([[for i=1,4 do a=1 end]], {1,1,1,1})
 189
 190_G.a = nil
 191
 192
 193do   -- 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
 210end
 211_G.a = nil
 212
 213
 214do   -- 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
 254end
 255
 256print'+'
 257
 258-- invalid levels in [gs]etlocal
 259assert(not pcall(debug.getlocal, 20, 1))
 260assert(not pcall(debug.setlocal, -1, 1, 10))
 261
 262
 263-- parameter names
 264local function foo (a,b,...) local d, e end
 265local co = coroutine.create(foo)
 266
 267assert(debug.getlocal(foo, 1) == 'a')
 268assert(debug.getlocal(foo, 2) == 'b')
 269assert(not debug.getlocal(foo, 3))
 270assert(debug.getlocal(co, foo, 1) == 'a')
 271assert(debug.getlocal(co, foo, 2) == 'b')
 272assert(not debug.getlocal(co, foo, 3))
 273
 274assert(not debug.getlocal(print, 1))
 275
 276
 277local function foo () return (debug.getlocal(1, -1)) end
 278assert(not foo(10))
 279
 280
 281-- varargs
 282local 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
 297end
 298
 299foo()
 300foo(print)
 301foo(200, 3, 4)
 302local a = {}
 303for i = 1, (_soft and 100 or 1000) do a[i] = i end
 304foo(table.unpack(a))
 305
 306
 307
 308do   -- 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)
 323end
 324_ENV.a = nil
 325
 326
 327-- hook table has weak keys
 328assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k')
 329
 330
 331a = {}; local L = nil
 332local glob = 1
 333local oldglob = glob
 334debug.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
 348end, "crl")
 349
 350
 351function 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)
 364end
 365
 366function foo()
 367  glob = glob+1
 368  assert(debug.getinfo(1, "l").currentline == L+1)
 369end; foo()  -- set L
 370-- check line counting inside strings and empty lines
 371
 372local _ = 'alo\
 373alo' .. [[
 374
 375]]
 376--[[
 377]]
 378assert(debug.getinfo(1, "l").currentline == L+11)  -- check count of lines
 379
 380
 381function 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
 393end
 394
 395g()
 396
 397
 398assert(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
 403local n, v = debug.getlocal(0, 1)
 404assert(v == 0 and n == "(C temporary)")
 405local n, v = debug.getlocal(0, 2)
 406assert(v == 2 and n == "(C temporary)")
 407assert(not debug.getlocal(0, 3))
 408assert(not debug.getlocal(0, 0))
 409
 410function 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
 415end
 416
 417function g(a,b) return (a+1) + f() end
 418
 419assert(g(0,0) == 30)
 420 
 421_G.f, _G.g = nil
 422
 423debug.sethook(nil);
 424assert(not debug.gethook())
 425
 426
 427-- minimal tests for setuservalue/getuservalue
 428do
 429  assert(not debug.setuservalue(io.stdin, 10))
 430  local a, b = debug.getuservalue(io.stdin, 10)
 431  assert(a == nil and not b)
 432end
 433
 434-- testing iteraction between multiple values x hooks
 435do
 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)
 447end
 448
 449
 450-- testing access to function arguments
 451
 452local 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
 462end
 463
 464
 465local X = nil
 466a = {}
 467function a:f (a, b, ...) local arg = {...}; local c = 13 end
 468debug.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")
 482end, "c")
 483
 484a:f(1,2,3,4,5)
 485assert(X.self == a and X.a == 1   and X.b == 2 and X.c == nil)
 486assert(XX == 12)
 487assert(not debug.gethook())
 488_G.XX = nil
 489
 490
 491-- testing access to local variables in return hook (bug in 5.2)
 492do
 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
 516end
 517
 518
 519local function eqseq (t1, t2)
 520  assert(#t1 == #t2)
 521  for i = 1, #t1 do
 522    assert(t1[i] == t2[i])
 523  end
 524end
 525
 526
 527do  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()
 560end
 561
 562
 563
 564-- testing upvalue access
 565local 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
 576end
 577
 578local a,b,c = 1,2,3
 579local function foo1 (a) b = a; return c end
 580local function foo2 (x) a = x; return c+b end
 581assert(not debug.getupvalue(foo1, 3))
 582assert(not debug.getupvalue(foo1, 0))
 583assert(not debug.setupvalue(foo1, 3, "xuxu"))
 584local t = getupvalues(foo1)
 585assert(t.a == nil and t.b == 2 and t.c == 3)
 586t = getupvalues(foo2)
 587assert(t.a == 1 and t.b == 2 and t.c == 3)
 588assert(debug.setupvalue(foo1, 1, "xuxu") == "b")
 589assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu")
 590-- upvalues of C functions are allways "called" "" (the empty string)
 591assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "")  
 592
 593
 594-- testing count hooks
 595local a=0
 596debug.sethook(function (e) a=a+1 end, "", 1)
 597a=0; for i=1,1000 do end; assert(1000 < a and a < 1012)
 598debug.sethook(function (e) a=a+1 end, "", 4)
 599a=0; for i=1,1000 do end; assert(250 < a and a < 255)
 600local f,m,c = debug.gethook()
 601assert(m == "" and c == 4)
 602debug.sethook(function (e) a=a+1 end, "", 4000)
 603a=0; for i=1,1000 do end; assert(a == 0)
 604
 605do
 606  debug.sethook(print, "", 2^24 - 1)   -- count upperbound
 607  local f,m,c = debug.gethook()
 608  assert(({debug.gethook()})[3] == 2^24 - 1)
 609end
 610
 611debug.sethook()
 612
 613local g, g1
 614
 615-- tests for tail calls
 616local 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
 625end
 626
 627function g(x) return f(x) end
 628
 629function g1(x) g(x) end
 630
 631local function h (x) local f=g1; return f(x) end
 632
 633h(true)
 634
 635local b = {}
 636debug.sethook(function (e) table.insert(b, e) end, "cr")
 637h(false)
 638debug.sethook()
 639local res = {"return",   -- first return (from sethook)
 640  "call", "tail call", "call", "tail call",
 641  "return", "return",
 642  "call",    -- last call (to sethook)
 643}
 644for i = 1, #res do assert(res[i] == table.remove(b, 1)) end
 645
 646b = 0
 647debug.sethook(function (e)
 648                if e == "tail call" then
 649                  b = b + 1
 650                  assert(debug.getinfo(2, "t").istailcall == true)
 651                else
 652                  assert(debug.getinfo(2, "t").istailcall == false)
 653                end
 654              end, "c")
 655h(false)
 656debug.sethook()
 657assert(b == 2)   -- two tail calls
 658
 659local lim = _soft and 3000 or 30000
 660local function foo (x)
 661  if x==0 then
 662    assert(debug.getinfo(2).what == "main")
 663    local info = debug.getinfo(1)
 664    assert(info.istailcall == true and info.func == foo)
 665  else return foo(x-1)
 666  end
 667end
 668
 669foo(lim)
 670
 671
 672print"+"
 673
 674
 675-- testing local function information
 676co = load[[
 677  local A = function ()
 678    return x
 679  end
 680  return
 681]]
 682
 683local a = 0
 684-- 'A' should be visible to debugger only after its complete definition
 685debug.sethook(function (e, l)
 686  if l == 3 then a = a + 1; assert(debug.getlocal(2, 1) == "(temporary)")
 687  elseif l == 4 then a = a + 1; assert(debug.getlocal(2, 1) == "A")
 688  end
 689end, "l")
 690co()  -- run local function definition
 691debug.sethook()  -- turn off hook
 692assert(a == 2)   -- ensure all two lines where hooked
 693
 694-- testing traceback
 695
 696assert(debug.traceback(print) == print)
 697assert(debug.traceback(print, 4) == print)
 698assert(string.find(debug.traceback("hi", 4), "^hi\n"))
 699assert(string.find(debug.traceback("hi"), "^hi\n"))
 700assert(not string.find(debug.traceback("hi"), "'debug.traceback'"))
 701assert(string.find(debug.traceback("hi", 0), "'debug.traceback'"))
 702assert(string.find(debug.traceback(), "^stack traceback:\n"))
 703
 704do  -- C-function names in traceback
 705  local st, msg = (function () return pcall end)()(debug.traceback)
 706  assert(st == true and string.find(msg, "pcall"))
 707end
 708
 709
 710-- testing nparams, nups e isvararg
 711local t = debug.getinfo(print, "u")
 712assert(t.isvararg == true and t.nparams == 0 and t.nups == 0)
 713
 714t = debug.getinfo(function (a,b,c) end, "u")
 715assert(t.isvararg == false and t.nparams == 3 and t.nups == 0)
 716
 717t = debug.getinfo(function (a,b,...) return t[a] end, "u")
 718assert(t.isvararg == true and t.nparams == 2 and t.nups == 1)
 719
 720t = debug.getinfo(1)   -- main
 721assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and
 722       debug.getupvalue(t.func, 1) == "_ENV")
 723
 724t = debug.getinfo(math.sin)   -- C function
 725assert(t.isvararg == true and t.nparams == 0 and t.nups == 0)
 726
 727t = debug.getinfo(string.gmatch("abc", "a"))   -- C closure
 728assert(t.isvararg == true and t.nparams == 0 and t.nups > 0)
 729
 730
 731
 732-- testing debugging of coroutines
 733
 734local function checktraceback (co, p, level)
 735  local tb = debug.traceback(co, nil, level)
 736  local i = 0
 737  for l in string.gmatch(tb, "[^\n]+\n?") do
 738    assert(i == 0 or string.find(l, p[i]))
 739    i = i+1
 740  end
 741  assert(p[i] == undef)
 742end
 743
 744
 745local function f (n)
 746  if n > 0 then f(n-1)
 747  else coroutine.yield() end
 748end
 749
 750local co = coroutine.create(f)
 751coroutine.resume(co, 3)
 752checktraceback(co, {"yield", "db.lua", "db.lua", "db.lua", "db.lua"})
 753checktraceback(co, {"db.lua", "db.lua", "db.lua", "db.lua"}, 1)
 754checktraceback(co, {"db.lua", "db.lua", "db.lua"}, 2)
 755checktraceback(co, {"db.lua"}, 4)
 756checktraceback(co, {}, 40)
 757
 758
 759co = coroutine.create(function (x)
 760       local a = 1
 761       coroutine.yield(debug.getinfo(1, "l"))
 762       coroutine.yield(debug.getinfo(1, "l").currentline)
 763       return a
 764     end)
 765
 766local tr = {}
 767local foo = function (e, l) if l then table.insert(tr, l) end end
 768debug.sethook(co, foo, "lcr")
 769
 770local _, l = coroutine.resume(co, 10)
 771local x = debug.getinfo(co, 1, "lfLS")
 772assert(x.currentline == l.currentline and x.activelines[x.currentline])
 773assert(type(x.func) == "function")
 774for i=x.linedefined + 1, x.lastlinedefined do
 775  assert(x.activelines[i])
 776  x.activelines[i] = undef
 777end
 778assert(next(x.activelines) == nil)   -- no 'extra' elements
 779assert(not debug.getinfo(co, 2))
 780local a,b = debug.getlocal(co, 1, 1)
 781assert(a == "x" and b == 10)
 782a,b = debug.getlocal(co, 1, 2)
 783assert(a == "a" and b == 1)
 784debug.setlocal(co, 1, 2, "hi")
 785assert(debug.gethook(co) == foo)
 786assert(#tr == 2 and
 787       tr[1] == l.currentline-1 and tr[2] == l.currentline)
 788
 789a,b,c = pcall(coroutine.resume, co)
 790assert(a and b and c == l.currentline+1)
 791checktraceback(co, {"yield", "in function <"})
 792
 793a,b = coroutine.resume(co)
 794assert(a and b == "hi")
 795assert(#tr == 4 and tr[4] == l.currentline+2)
 796assert(debug.gethook(co) == foo)
 797assert(not debug.gethook())
 798checktraceback(co, {})
 799
 800
 801-- check get/setlocal in coroutines
 802co = coroutine.create(function (x)
 803  local a, b = coroutine.yield(x)
 804  assert(a == 100 and b == nil)
 805  return x
 806end)
 807a, b = coroutine.resume(co, 10)
 808assert(a and b == 10)
 809a, b = debug.getlocal(co, 1, 1)
 810assert(a == "x" and b == 10)
 811assert(not debug.getlocal(co, 1, 5))
 812assert(debug.setlocal(co, 1, 1, 30) == "x")
 813assert(not debug.setlocal(co, 1, 5, 40))
 814a, b = coroutine.resume(co, 100)
 815assert(a and b == 30)
 816
 817
 818-- check traceback of suspended (or dead with error) coroutines
 819
 820function f(i)
 821  if i == 0 then error(i)
 822  else coroutine.yield(); f(i-1)
 823  end
 824end
 825
 826
 827co = coroutine.create(function (x) f(x) end)
 828a, b = coroutine.resume(co, 3)
 829t = {"'coroutine.yield'", "'f'", "in function <"}
 830while coroutine.status(co) == "suspended" do
 831  checktraceback(co, t)
 832  a, b = coroutine.resume(co)
 833  table.insert(t, 2, "'f'")   -- one more recursive call to 'f'
 834end
 835t[1] = "'error'"
 836checktraceback(co, t)
 837
 838
 839-- test acessing line numbers of a coroutine from a resume inside
 840-- a C function (this is a known bug in Lua 5.0)
 841
 842local function g(x)
 843    coroutine.yield(x)
 844end
 845
 846local function f (i)
 847  debug.sethook(function () end, "l")
 848  for j=1,1000 do
 849    g(i+j)
 850  end
 851end
 852
 853local co = coroutine.wrap(f)
 854co(10)
 855pcall(co)
 856pcall(co)
 857
 858
 859assert(type(debug.getregistry()) == "table")
 860
 861
 862-- test tagmethod information
 863local a = {}
 864local function f (t)
 865  local info = debug.getinfo(1);
 866  assert(info.namewhat == "metamethod")
 867  a.op = info.name
 868  return info.name
 869end
 870setmetatable(a, {
 871  __index = f; __add = f; __div = f; __mod = f; __concat = f; __pow = f;
 872  __mul = f; __idiv = f; __unm = f; __len = f; __sub = f;
 873  __shl = f; __shr = f; __bor = f; __bxor = f;
 874  __eq = f; __le = f; __lt = f; __unm = f; __len = f; __band = f;
 875  __bnot = f;
 876})
 877
 878local b = setmetatable({}, getmetatable(a))
 879
 880assert(a[3] == "index" and a^3 == "pow" and a..a == "concat")
 881assert(a/3 == "div" and 3%a == "mod")
 882assert(a+3 == "add" and 3-a == "sub" and a*3 == "mul" and
 883       -a == "unm" and #a == "len" and a&3 == "band")
 884assert(a + 30000 == "add" and a - 3.0 == "sub" and a * 3.0 == "mul" and
 885       -a == "unm" and #a == "len" and a & 3 == "band")
 886assert(a|3 == "bor" and 3~a == "bxor" and a<<3 == "shl" and a>>1 == "shr")
 887assert (a==b and a.op == "eq")
 888assert (a>=b and a.op == "le")
 889assert ("x">=a and a.op == "le")
 890assert (a>b and a.op == "lt")
 891assert (a>10 and a.op == "lt")
 892assert(~a == "bnot")
 893
 894do   -- testing for-iterator name
 895  local function f()
 896    assert(debug.getinfo(1).name == "for iterator")
 897  end
 898
 899  for i in f do end
 900end
 901
 902
 903do   -- testing debug info for finalizers
 904  local name = nil
 905
 906  -- create a piece of garbage with a finalizer
 907  setmetatable({}, {__gc = function ()
 908    local t = debug.getinfo(1)   -- get function information
 909    assert(t.namewhat == "metamethod")
 910    name = t.name
 911  end})
 912
 913  -- repeat until previous finalizer runs (setting 'name')
 914  repeat local a = {} until name
 915  assert(name == "__gc")
 916end
 917
 918
 919do
 920  print("testing traceback sizes")
 921
 922  local function countlines (s)
 923    return select(2, string.gsub(s, "\n", ""))
 924  end
 925
 926  local function deep (lvl, n)
 927    if lvl == 0 then
 928      return (debug.traceback("message", n))
 929    else
 930      return (deep(lvl-1, n))
 931    end
 932  end
 933
 934  local function checkdeep (total, start)
 935    local s = deep(total, start)
 936    local rest = string.match(s, "^message\nstack traceback:\n(.*)$")
 937    local cl = countlines(rest)
 938    -- at most 10 lines in first part, 11 in second, plus '...'
 939    assert(cl <= 10 + 11 + 1)
 940    local brk = string.find(rest, "%.%.%.\t%(skip")
 941    if brk then   -- does message have '...'?
 942      local rest1 = string.sub(rest, 1, brk)
 943      local rest2 = string.sub(rest, brk, #rest)
 944      assert(countlines(rest1) == 10 and countlines(rest2) == 11)
 945    else
 946      assert(cl == total - start + 2)
 947    end
 948  end
 949
 950  for d = 1, 51, 10 do
 951    for l = 1, d do
 952      -- use coroutines to ensure complete control of the stack
 953      coroutine.wrap(checkdeep)(d, l)
 954    end
 955  end
 956
 957end
 958
 959
 960print("testing debug functions on chunk without debug info")
 961local prog = [[-- program to be loaded without debug information (strip)
 962local debug = require'debug'
 963local a = 12  -- a local variable
 964
 965local n, v = debug.getlocal(1, 1)
 966assert(n == "(temporary)" and v == debug)   -- unkown name but known value
 967n, v = debug.getlocal(1, 2)
 968assert(n == "(temporary)" and v == 12)   -- unkown name but known value
 969
 970-- a function with an upvalue
 971local f = function () local x; return a end
 972n, v = debug.getupvalue(f, 1)
 973assert(n == "(no name)" and v == 12)
 974assert(debug.setupvalue(f, 1, 13) == "(no name)")
 975assert(a == 13)
 976
 977local t = debug.getinfo(f)
 978assert(t.name == nil and t.linedefined > 0 and
 979       t.lastlinedefined == t.linedefined and
 980       t.short_src == "?")
 981assert(debug.getinfo(1).currentline == -1)
 982
 983t = debug.getinfo(f, "L").activelines
 984assert(next(t) == nil)    -- active lines are empty
 985
 986-- dump/load a function without debug info
 987f = load(string.dump(f))
 988
 989t = debug.getinfo(f)
 990assert(t.name == nil and t.linedefined > 0 and
 991       t.lastlinedefined == t.linedefined and
 992       t.short_src == "?")
 993assert(debug.getinfo(1).currentline == -1)
 994
 995return a
 996]]
 997
 998
 999-- load 'prog' without debug info
1000local f = assert(load(string.dump(load(prog), true)))
1001
1002assert(f() == 13)
1003
1004do   -- bug in 5.4.0: line hooks in stripped code
1005  local function foo ()
1006    local a = 1
1007    local b = 2
1008    return b
1009  end
1010
1011  local s = load(string.dump(foo, true))
1012  local line = true
1013  debug.sethook(function (e, l)
1014    assert(e == "line")
1015    line = l
1016  end, "l")
1017  assert(s() == 2); debug.sethook(nil)
1018  assert(line == nil)  -- hook called withoug debug info for 1st instruction
1019end
1020
1021do   -- tests for 'source' in binary dumps
1022  local prog = [[
1023    return function (x)
1024      return function (y) 
1025        return x + y
1026      end
1027    end
1028  ]]
1029  local name = string.rep("x", 1000)
1030  local p = assert(load(prog, name))
1031  -- load 'p' as a binary chunk with debug information
1032  local c = string.dump(p)
1033  assert(#c > 1000 and #c < 2000)   -- no repetition of 'source' in dump
1034  local f = assert(load(c))
1035  local g = f()
1036  local h = g(3)
1037  assert(h(5) == 8)
1038  assert(debug.getinfo(f).source == name and   -- all functions have 'source'
1039         debug.getinfo(g).source == name and 
1040         debug.getinfo(h).source == name)
1041  -- again, without debug info
1042  local c = string.dump(p, true)
1043  assert(#c < 500)   -- no 'source' in dump
1044  local f = assert(load(c))
1045  local g = f()
1046  local h = g(30)
1047  assert(h(50) == 80)
1048  assert(debug.getinfo(f).source == '=?' and   -- no function has 'source'
1049         debug.getinfo(g).source == '=?' and 
1050         debug.getinfo(h).source == '=?')
1051end
1052
1053print"OK"
1054