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