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