github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/testdata/lua-5.3.3-tests/db.lua (about) 1 -- $Id: db.lua,v 1.78 2015/10/02 15:47:27 roberto Exp $ 2 3 -- testing debug library 4 5 local debug = require "debug" 6 7 local function dostring(s) return assert(load(s))() end 8 9 print"testing debug library and debug information" 10 11 do 12 local a=1 13 end 14 15 assert(not debug.gethook()) 16 17 function test (s, l, p) 18 collectgarbage() -- avoid gc during trace 19 local function f (event, line) 20 assert(event == 'line') 21 local l = table.remove(l, 1) 22 if p then print(l, line) end 23 assert(l == line, "wrong trace!!") 24 end 25 debug.sethook(f,"l"); load(s)(); debug.sethook() 26 assert(#l == 0) 27 end 28 29 do 30 assert(not pcall(debug.getinfo, print, "X")) -- invalid option 31 assert(not debug.getinfo(1000)) -- out of range level 32 assert(not debug.getinfo(-1)) -- out of range level 33 local a = debug.getinfo(print) 34 assert((a.what == "C" and a.short_src == "[C]") or (a.what == "Go" and a.short_src == "[Go]")) 35 a = debug.getinfo(print, "L") 36 assert(a.activelines == nil) 37 local b = debug.getinfo(test, "SfL") 38 assert(b.name == nil and b.what == "Lua" and b.linedefined == 17 and 39 b.lastlinedefined == b.linedefined + 10 and 40 b.func == test and not string.find(b.short_src, "%[")) 41 assert(b.activelines[b.linedefined + 1] and 42 b.activelines[b.lastlinedefined]) 43 assert(not b.activelines[b.linedefined] and 44 not b.activelines[b.lastlinedefined + 1]) 45 end 46 47 -- test file and string names truncation 48 a = "function f () end" 49 local function dostring (s, x) return load(s, x)() end 50 dostring(a) 51 assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a)) 52 dostring(a..string.format("; %s\n=1", string.rep('p', 400))) 53 assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$')) 54 dostring(a..string.format("; %s=1", string.rep('p', 400))) 55 assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$')) 56 dostring("\n"..a) 57 assert(debug.getinfo(f).short_src == '[string "..."]') 58 -- TODO or spec 59 -- dostring(a, "") 60 -- assert(debug.getinfo(f).short_src == '[string ""]') 61 dostring(a, "@xuxu") 62 assert(debug.getinfo(f).short_src == "xuxu") 63 dostring(a, "@"..string.rep('p', 1000)..'t') 64 assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$")) 65 dostring(a, "=xuxu") 66 assert(debug.getinfo(f).short_src == "xuxu") 67 dostring(a, string.format("=%s", string.rep('x', 500))) 68 assert(string.find(debug.getinfo(f).short_src, "^x*$")) 69 dostring(a, "=") 70 assert(debug.getinfo(f).short_src == "") 71 a = nil; f = nil; 72 73 74 repeat 75 local g = {x = function () 76 local a = debug.getinfo(2) 77 assert(a.name == 'f' and a.namewhat == 'local') 78 a = debug.getinfo(1) 79 assert(a.name == 'x' and a.namewhat == 'field') 80 return 'xixi' 81 end} 82 local f = function () return 1+1 and (not 1 or g.x()) end 83 assert(f() == 'xixi') 84 g = debug.getinfo(f) 85 assert(g.what == "Lua" and g.func == f and g.namewhat == "" and not g.name) 86 87 function f (x, name) -- local! 88 name = name or 'f' 89 local a = debug.getinfo(1) 90 assert(a.name == name and a.namewhat == 'local') 91 return x 92 end 93 94 -- breaks in different conditions 95 if 3>4 then break end; f() 96 if 3<4 then a=1 else break end; f() 97 while 1 do local x=10; break end; f() 98 local b = 1 99 if 3>4 then return math.sin(1) end; f() 100 a = 3<4; f() 101 a = 3<4 or 1; f() 102 repeat local x=20; if 4>3 then f() else break end; f() until 1 103 g = {} 104 f(g).x = f(2) and f(10)+f(9) 105 assert(g.x == f(19)) 106 function g(x) if not x then return 3 end return (x('a', 'x')) end 107 assert(g(f) == 'a') 108 until 1 109 110 -- TODO or spec 111 -- test([[if 112 -- math.sin(1) 113 -- then 114 -- a=1 115 -- else 116 -- a=2 117 -- end 118 -- ]], {2,3,4,7}) 119 120 -- test([[-- 121 -- if nil then 122 -- a=1 123 -- else 124 -- a=2 125 -- end 126 -- ]], {2,5,6}) 127 128 -- test([[a=1 129 -- repeat 130 -- a=a+1 131 -- until a==3 132 -- ]], {1,3,4,3,4}) 133 134 -- test([[ do 135 -- return 136 -- end 137 -- ]], {2}) 138 139 -- test([[local a 140 -- a=1 141 -- while a<=3 do 142 -- a=a+1 143 -- end 144 -- ]], {1,2,3,4,3,4,3,4,3,5}) 145 146 -- test([[while math.sin(1) do 147 -- if math.sin(1) 148 -- then break 149 -- end 150 -- end 151 -- a=1]], {1,2,3,6}) 152 153 -- test([[for i=1,3 do 154 -- a=i 155 -- end 156 -- ]], {1,2,1,2,1,2,1,3}) 157 158 -- test([[for i,v in pairs{'a','b'} do 159 -- a=tostring(i) .. v 160 -- end 161 -- ]], {1,2,1,2,1,3}) 162 163 -- test([[for i=1,4 do a=1 end]], {1,1,1,1,1}) 164 165 166 167 print'+' 168 169 -- invalid levels in [gs]etlocal 170 assert(not pcall(debug.getlocal, 20, 1)) 171 assert(not pcall(debug.setlocal, -1, 1, 10)) 172 173 174 -- parameter names 175 local function foo (a,b,...) local d, e end 176 local co = coroutine.create(foo) 177 178 assert(debug.getlocal(foo, 1) == 'a') 179 assert(debug.getlocal(foo, 2) == 'b') 180 assert(not debug.getlocal(foo, 3)) 181 assert(debug.getlocal(co, foo, 1) == 'a') 182 assert(debug.getlocal(co, foo, 2) == 'b') 183 assert(not debug.getlocal(co, foo, 3)) 184 185 assert(not debug.getlocal(print, 1)) 186 187 188 -- varargs 189 local function foo (a, ...) 190 local t = table.pack(...) 191 for i = 1, t.n do 192 local n, v = debug.getlocal(1, -i) 193 assert(n == "(*vararg)" and v == t[i]) 194 end 195 assert(not debug.getlocal(1, -(t.n + 1))) 196 assert(not debug.setlocal(1, -(t.n + 1), 30)) 197 if t.n > 0 then 198 (function (x) 199 assert(debug.setlocal(2, -1, x) == "(*vararg)") 200 assert(debug.setlocal(2, -t.n, x) == "(*vararg)") 201 end)(430) 202 assert(... == 430) 203 end 204 end 205 206 foo() 207 foo(print) 208 foo(200, 3, 4) 209 local a = {} 210 for i = 1, (_soft and 100 or 1000) do a[i] = i end 211 foo(table.unpack(a)) 212 a = nil 213 214 -- access to vararg in non-vararg function 215 local function foo () return debug.getlocal(1, -1) end 216 assert(not foo(10)) 217 218 219 do -- test hook presence in debug info 220 assert(not debug.gethook()) 221 local count = 0 222 local function f () 223 assert(debug.getinfo(1).namewhat == "hook") 224 local sndline = string.match(debug.traceback(), "\n(.-)\n") 225 assert(string.find(sndline, "hook")) 226 count = count + 1 227 end 228 debug.sethook(f, "l") 229 local a = 0 230 _ENV.a = a 231 a = 1 232 debug.sethook() 233 -- assert(count == 4) 234 end 235 236 237 a = {}; L = nil 238 local glob = 1 239 local oldglob = glob 240 debug.sethook(function (e,l) 241 collectgarbage() -- force GC during a hook 242 local f, m, c = debug.gethook() 243 assert(m == 'crl' and c == 0) 244 if e == "line" then 245 if glob ~= oldglob then 246 L = l-1 -- get the first line where "glob" has changed 247 oldglob = glob 248 end 249 elseif e == "call" then 250 local f = debug.getinfo(2, "f").func 251 a[f] = 1 252 else assert(e == "return") 253 end 254 end, "crl") 255 256 257 function f(a,b) 258 collectgarbage() 259 local _, x = debug.getlocal(1, 1) 260 local _, y = debug.getlocal(1, 2) 261 assert(x == a and y == b) 262 assert(debug.setlocal(2, 3, "pera") == "AA".."AA") 263 assert(debug.setlocal(2, 4, "maçã") == "B") 264 x = debug.getinfo(2) 265 assert(x.func == g and x.what == "Lua" and x.name == 'g' and 266 x.nups == 2 and string.find(x.source, "^@.*db%.lua$")) 267 glob = glob+1 268 assert(debug.getinfo(1, "l").currentline == L+1) 269 assert(debug.getinfo(1, "l").currentline == L+2) 270 end 271 272 function foo() 273 glob = glob+1 274 assert(debug.getinfo(1, "l").currentline == L+1) 275 end; foo() -- set L 276 -- check line counting inside strings and empty lines 277 278 _ = 'alo\ 279 alo' .. [[ 280 281 ]] 282 --[[ 283 ]] 284 assert(debug.getinfo(1, "l").currentline == L+11) -- check count of lines 285 286 287 function g(...) 288 local arg = {...} 289 do local a,b,c; a=math.sin(40); end 290 local feijao 291 local AAAA,B = "xuxu", "mamão" 292 f(AAAA,B) 293 assert(AAAA == "pera" and B == "maçã") 294 do 295 local B = 13 296 local x,y = debug.getlocal(1,5) 297 assert(x == 'B' and y == 13) 298 end 299 end 300 301 g() 302 303 assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print]) 304 305 -- TODO or spec have no plan to support getlocal for GoFunction 306 -- tests for manipulating non-registered locals (C and Lua temporaries) 307 308 -- local n, v = debug.getlocal(0, 1) 309 -- assert(v == 0 and n == "(*temporary)") 310 -- local n, v = debug.getlocal(0, 2) 311 -- assert(v == 2 and n == "(*temporary)") 312 -- assert(not debug.getlocal(0, 3)) 313 -- assert(not debug.getlocal(0, 0)) 314 315 -- function f() 316 -- print(debug.getlocal(2, 3)) 317 -- assert(select(2, debug.getlocal(2,3)) == 1) 318 -- assert(not debug.getlocal(2,4)) 319 -- debug.setlocal(2, 3, 10) 320 -- return 20 321 -- end 322 323 -- function g(a,b) return (a+1) + f() end 324 325 -- assert(g(0,0) == 30) 326 327 328 debug.sethook(nil); 329 assert(debug.gethook() == nil) 330 331 332 -- testing access to function arguments 333 334 local function collectlocals (level) 335 tab = {} 336 for i = 1, math.huge do 337 local n, v = debug.getlocal(level + 1, i) 338 if not (n and string.find(n, "^[a-zA-Z0-9_]+$")) then 339 break -- consider only real variables 340 end 341 tab[n] = v 342 end 343 return tab 344 end 345 346 347 X = nil 348 a = {} 349 function a:f (a, b, ...) local arg = {...}; local c = 13 end 350 debug.sethook(function (e) 351 assert(e == "call") 352 dostring("XX = 12") -- test dostring inside hooks 353 -- testing errors inside hooks 354 assert(not pcall(load("a='joao'+1"))) 355 debug.sethook(function (e, l) 356 assert(debug.getinfo(2, "l").currentline == l) 357 local f,m,c = debug.gethook() 358 assert(e == "line") 359 assert(m == 'l' and c == 0) 360 debug.sethook(nil) -- hook is called only once 361 assert(not X) -- check that 362 X = collectlocals(2) 363 end, "l") 364 end, "c") 365 366 a:f(1,2,3,4,5) 367 assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil) 368 assert(XX == 12) 369 assert(debug.gethook() == nil) 370 371 372 -- testing access to local variables in return hook (bug in 5.2) 373 do 374 local function foo (a, b) 375 do local x,y,z end 376 local c, d = 10, 20 377 return 378 end 379 380 local function aux () 381 if debug.getinfo(2).name == "foo" then 382 foo = nil -- to signal that it found 'foo' 383 local tab = {a = 100, b = 200, c = 10, d = 20} 384 for n, v in pairs(collectlocals(2)) do 385 assert(tab[n] == v) 386 tab[n] = nil 387 end 388 assert(next(tab) == nil) -- 'tab' must be empty 389 end 390 end 391 392 debug.sethook(aux, "r"); foo(100, 200); debug.sethook() 393 assert(foo == nil) 394 end 395 396 -- testing upvalue access 397 local function getupvalues (f) 398 local t = {} 399 local i = 1 400 while true do 401 local name, value = debug.getupvalue(f, i) 402 if not name then break end 403 assert(not t[name]) 404 t[name] = value 405 i = i + 1 406 end 407 return t 408 end 409 410 local a,b,c = 1,2,3 411 local function foo1 (a) b = a; return c end 412 local function foo2 (x) a = x; return c+b end 413 assert(not debug.getupvalue(foo1, 3)) 414 assert(not debug.getupvalue(foo1, 0)) 415 assert(not debug.setupvalue(foo1, 3, "xuxu")) 416 local t = getupvalues(foo1) 417 assert(t.a == nil and t.b == 2 and t.c == 3) 418 t = getupvalues(foo2) 419 assert(t.a == 1 and t.b == 2 and t.c == 3) 420 assert(debug.setupvalue(foo1, 1, "xuxu") == "b") 421 assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu") 422 -- TODO or spec have no plan to support getlocal for GoFunction 423 -- upvalues of C functions are allways "called" "" (the empty string) 424 -- assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "") 425 426 427 -- testing count hooks 428 local a=0 429 debug.sethook(function (e) a=a+1 end, "", 1) 430 a=0; for i=1,1000 do end; assert(1000 < a and a < 1012) 431 debug.sethook(function (e) a=a+1 end, "", 4) 432 a=0; for i=1,1000 do end; assert(250 < a and a < 255) 433 local f,m,c = debug.gethook() 434 assert(m == "" and c == 4) 435 debug.sethook(function (e) a=a+1 end, "", 4000) 436 a=0; for i=1,1000 do end; assert(a == 0) 437 438 do 439 debug.sethook(print, "", 2^24 - 1) -- count upperbound 440 local f,m,c = debug.gethook() 441 assert(({debug.gethook()})[3] == 2^24 - 1) 442 end 443 444 debug.sethook() 445 446 447 -- tests for tail calls 448 local function f (x) 449 if x then 450 assert(debug.getinfo(1, "S").what == "Lua") 451 assert(debug.getinfo(1, "t").istailcall == true) 452 local tail = debug.getinfo(2) 453 assert(tail.func == g1 and tail.istailcall == true) 454 assert(debug.getinfo(3, "S").what == "main") 455 print"+" 456 end 457 end 458 459 function g(x) return f(x) end 460 461 function g1(x) g(x) end 462 463 local function h (x) local f=g1; return f(x) end 464 465 h(true) 466 467 local b = {} 468 debug.sethook(function (e) table.insert(b, e) end, "cr") 469 h(false) 470 debug.sethook() 471 local res = {"return", -- first return (from sethook) 472 "call", "tail call", "call", "tail call", 473 "return", "return", 474 "call", -- last call (to sethook) 475 } 476 for i = 1, #res do assert(res[i] == table.remove(b, 1)) end 477 478 b = 0 479 debug.sethook(function (e) 480 if e == "tail call" then 481 b = b + 1 482 assert(debug.getinfo(2, "t").istailcall == true) 483 else 484 assert(debug.getinfo(2, "t").istailcall == false) 485 end 486 end, "c") 487 h(false) 488 debug.sethook() 489 assert(b == 2) -- two tail calls 490 491 lim = _soft and 3000 or 30000 492 local function foo (x) 493 if x==0 then 494 assert(debug.getinfo(2).what == "main") 495 local info = debug.getinfo(1) 496 assert(info.istailcall == true and info.func == foo) 497 else return foo(x-1) 498 end 499 end 500 501 foo(lim) 502 503 504 print"+" 505 506 507 -- TODO or spec plua produce different byte codes 508 -- testing local function information 509 -- co = load[[ 510 -- local A = function () 511 -- return x 512 -- end 513 -- return 514 -- ]] 515 516 -- local a = 0 517 -- -- 'A' should be visible to debugger only after its complete definition 518 -- debug.sethook(function (e, l) 519 -- if l == 3 then a = a + 1; assert(debug.getlocal(2, 1) == "(*temporary)") 520 -- elseif l == 4 then a = a + 1; assert(debug.getlocal(2, 1) == "A") 521 -- end 522 -- end, "l") 523 -- co() -- run local function definition 524 -- debug.sethook() -- turn off hook 525 -- assert(a == 2) -- ensure all two lines where hooked 526 527 -- testing traceback 528 529 assert(debug.traceback(print) == print) 530 assert(debug.traceback(print, 4) == print) 531 assert(string.find(debug.traceback("hi", 4), "^hi\n")) 532 assert(string.find(debug.traceback("hi"), "^hi\n")) 533 assert(not string.find(debug.traceback("hi"), "'debug.traceback'")) 534 assert(string.find(debug.traceback("hi", 0), "'debug.traceback'")) 535 assert(string.find(debug.traceback(), "^stack traceback:\n")) 536 537 -- do -- C-function names in traceback 538 -- local st, msg = (function () return pcall end)()(debug.traceback) 539 -- assert(st == true and string.find(msg, "pcall")) 540 -- end 541 542 543 -- testing nparams, nups e isvararg 544 local t = debug.getinfo(print, "u") 545 assert(t.isvararg == true and t.nparams == 0 and t.nups == 0) 546 547 t = debug.getinfo(function (a,b,c) end, "u") 548 assert(t.isvararg == false and t.nparams == 3 and t.nups == 0) 549 550 t = debug.getinfo(function (a,b,...) return t[a] end, "u") 551 assert(t.isvararg == true and t.nparams == 2 and t.nups == 1) 552 553 t = debug.getinfo(1) -- main 554 assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and 555 debug.getupvalue(t.func, 1) == "_ENV") 556 557 558 559 560 -- testing debugging of coroutines 561 562 local function checktraceback (co, p, level) 563 local tb = debug.traceback(co, nil, level) 564 local i = 0 565 for l in string.gmatch(tb, "[^\n]+\n?") do 566 assert(i == 0 or string.find(l, p[i])) 567 i = i+1 568 end 569 assert(p[i] == nil) 570 end 571 572 573 local function f (n) 574 if n > 0 then f(n-1) 575 else coroutine.yield() end 576 end 577 578 local co = coroutine.create(f) 579 coroutine.resume(co, 3) 580 checktraceback(co, {"yield", "db.lua", "db.lua", "db.lua", "db.lua"}) 581 checktraceback(co, {"db.lua", "db.lua", "db.lua", "db.lua"}, 1) 582 checktraceback(co, {"db.lua", "db.lua", "db.lua"}, 2) 583 checktraceback(co, {"db.lua"}, 4) 584 checktraceback(co, {}, 40) 585 586 587 co = coroutine.create(function (x) 588 local a = 1 589 coroutine.yield(debug.getinfo(1, "l")) 590 coroutine.yield(debug.getinfo(1, "l").currentline) 591 return a 592 end) 593 594 local tr = {} 595 local foo = function (e, l) if l then table.insert(tr, l) end end 596 debug.sethook(co, foo, "lcr") 597 598 local _, l = coroutine.resume(co, 10) 599 local x = debug.getinfo(co, 1, "lfLS") 600 assert(x.currentline == l.currentline and x.activelines[x.currentline]) 601 assert(type(x.func) == "function") 602 for i=x.linedefined + 1, x.lastlinedefined do 603 assert(x.activelines[i]) 604 x.activelines[i] = nil 605 end 606 assert(next(x.activelines) == nil) -- no 'extra' elements 607 assert(not debug.getinfo(co, 2)) 608 local a,b = debug.getlocal(co, 1, 1) 609 assert(a == "x" and b == 10) 610 a,b = debug.getlocal(co, 1, 2) 611 assert(a == "a" and b == 1) 612 debug.setlocal(co, 1, 2, "hi") 613 assert(debug.gethook(co) == foo) 614 assert(#tr == 2 and 615 tr[1] == l.currentline-1 and tr[2] == l.currentline) 616 617 a,b,c = pcall(coroutine.resume, co) 618 assert(a and b and c == l.currentline+1) 619 checktraceback(co, {"yield", "in function <"}) 620 621 a,b = coroutine.resume(co) 622 assert(a and b == "hi") 623 assert(#tr == 4 and tr[4] == l.currentline+2) 624 assert(debug.gethook(co) == foo) 625 assert(not debug.gethook()) 626 checktraceback(co, {}) 627 628 629 -- check get/setlocal in coroutines 630 co = coroutine.create(function (x) 631 local a, b = coroutine.yield(x) 632 assert(a == 100 and b == nil) 633 return x 634 end) 635 a, b = coroutine.resume(co, 10) 636 assert(a and b == 10) 637 a, b = debug.getlocal(co, 1, 1) 638 assert(a == "x" and b == 10) 639 assert(not debug.getlocal(co, 1, 5)) 640 assert(debug.setlocal(co, 1, 1, 30) == "x") 641 assert(not debug.setlocal(co, 1, 5, 40)) 642 a, b = coroutine.resume(co, 100) 643 assert(a and b == 30) 644 645 646 -- check traceback of suspended (or dead with error) coroutines 647 648 function f(i) if i==0 then error(i) else coroutine.yield(); f(i-1) end end 649 650 co = coroutine.create(function (x) f(x) end) 651 a, b = coroutine.resume(co, 3) 652 t = {"'coroutine.yield'", "'f'", "in function <"} 653 while coroutine.status(co) == "suspended" do 654 checktraceback(co, t) 655 a, b = coroutine.resume(co) 656 table.insert(t, 2, "'f'") -- one more recursive call to 'f' 657 end 658 t[1] = "'error'" 659 checktraceback(co, t) 660 661 662 -- test acessing line numbers of a coroutine from a resume inside 663 -- a C function (this is a known bug in Lua 5.0) 664 665 local function g(x) 666 coroutine.yield(x) 667 end 668 669 local function f (i) 670 debug.sethook(function () end, "l") 671 for j=1,1000 do 672 g(i+j) 673 end 674 end 675 676 local co = coroutine.wrap(f) 677 co(10) 678 pcall(co) 679 pcall(co) 680 681 682 -- TODO or spec getregistry is not implemented 683 -- assert(type(debug.getregistry()) == "table") 684 685 686 -- test tagmethod information 687 local a = {} 688 local function f (t) 689 local info = debug.getinfo(1); 690 assert(info.namewhat == "metamethod") 691 a.op = info.name 692 return info.name 693 end 694 setmetatable(a, { 695 __index = f; __add = f; __div = f; __mod = f; __concat = f; __pow = f; 696 __mul = f; __idiv = f; __unm = f; __len = f; __sub = f; 697 __shl = f; __shr = f; __bor = f; __bxor = f; 698 __eq = f; __le = f; __lt = f; __unm = f; __len = f; __band = f; 699 __bnot = f; 700 }) 701 702 local b = setmetatable({}, getmetatable(a)) 703 704 assert(a[3] == "__index" and a^3 == "__pow" and a..a == "__concat") 705 assert(a/3 == "__div" and 3%a == "__mod") 706 assert(a+3 == "__add" and 3-a == "__sub" and a*3 == "__mul" and 707 -a == "__unm" and #a == "__len" and a&3 == "__band") 708 assert(a|3 == "__bor" and 3~a == "__bxor" and a<<3 == "__shl" and 709 a>>1 == "__shr") 710 assert (a==b and a.op == "__eq") 711 assert (a>=b and a.op == "__le") 712 assert (a>b and a.op == "__lt") 713 assert(~a == "__bnot") 714 715 do -- testing for-iterator name 716 local function f() 717 assert(debug.getinfo(1).name == "for iterator") 718 end 719 720 for i in f do end 721 end 722 723 do 724 print("testing traceback sizes") 725 726 local function countlines (s) 727 return select(2, string.gsub(s, "\n", "")) 728 end 729 730 local function deep (lvl, n) 731 if lvl == 0 then 732 return (debug.traceback("message", n)) 733 else 734 return (deep(lvl-1, n)) 735 end 736 end 737 738 local function checkdeep (total, start) 739 local s = deep(total, start) 740 local rest = string.match(s, "^message\nstack traceback:\n(.*)$") 741 local cl = countlines(rest) 742 -- at most 10 lines in first part, 11 in second, plus '...' 743 assert(cl <= 10 + 11 + 1) 744 local brk = string.find(rest, "%.%.%.") 745 if brk then -- does message have '...'? 746 local rest1 = string.sub(rest, 1, brk) 747 local rest2 = string.sub(rest, brk, #rest) 748 assert(countlines(rest1) == 10 and countlines(rest2) == 11) 749 else 750 assert(cl == total - start + 2) 751 end 752 end 753 754 for d = 1, 51, 10 do 755 for l = 1, d do 756 -- use coroutines to ensure complete control of the stack 757 coroutine.wrap(checkdeep)(d, l) 758 end 759 end 760 761 end 762 763 764 print("testing debug functions on chunk without debug info") 765 prog = [[-- program to be loaded without debug information 766 local debug = require'debug' 767 local a = 12 -- a local variable 768 769 local n, v = debug.getlocal(1, 1) 770 assert(n == "(*temporary)" and v == debug) -- unkown name but known value 771 n, v = debug.getlocal(1, 2) 772 assert(n == "(*temporary)" and v == 12) -- unkown name but known value 773 774 -- a function with an upvalue 775 local f = function () local x; return a end 776 n, v = debug.getupvalue(f, 1) 777 assert(n == "(*no name)" and v == 12) 778 assert(debug.setupvalue(f, 1, 13) == "(*no name)") 779 assert(a == 13) 780 781 local t = debug.getinfo(f) 782 assert(t.name == nil and t.linedefined > 0 and 783 t.lastlinedefined == t.linedefined and 784 t.short_src == "?") 785 assert(debug.getinfo(1).currentline == -1) 786 787 t = debug.getinfo(f, "L").activelines 788 assert(next(t) == nil) -- active lines are empty 789 790 -- dump/load a function without debug info 791 f = load(string.dump(f)) 792 793 t = debug.getinfo(f) 794 assert(t.name == nil and t.linedefined > 0 and 795 t.lastlinedefined == t.linedefined and 796 t.short_src == "?") 797 assert(debug.getinfo(1).currentline == -1) 798 799 return a 800 ]] 801 802 803 -- load 'prog' without debug info 804 local f = assert(load(string.dump(load(prog), true))) 805 806 assert(f() == 13) 807 808 do -- tests for 'source' in binary dumps 809 local prog = [[ 810 return function (x) 811 return function (y) 812 return x + y 813 end 814 end 815 ]] 816 local name = string.rep("x", 1000) 817 local p = assert(load(prog, name)) 818 -- load 'p' as a binary chunk with debug information 819 local c = string.dump(p) 820 assert(#c > 1000 and #c < 2000) -- no repetition of 'source' in dump 821 local f = assert(load(c)) 822 local g = f() 823 local h = g(3) 824 assert(h(5) == 8) 825 assert(debug.getinfo(f).source == name and -- all functions have 'source' 826 debug.getinfo(g).source == name and 827 debug.getinfo(h).source == name) 828 -- again, without debug info 829 local c = string.dump(p, true) 830 assert(#c < 500) -- no 'source' in dump 831 local f = assert(load(c)) 832 local g = f() 833 local h = g(30) 834 assert(h(50) == 80) 835 assert(debug.getinfo(f).source == '=?' and -- no function has 'source' 836 debug.getinfo(g).source == '=?' and 837 debug.getinfo(h).source == '=?') 838 end 839 840 print"OK" 841