diff options
Diffstat (limited to 'testes/db.lua')
-rw-r--r-- | testes/db.lua | 857 |
1 files changed, 857 insertions, 0 deletions
diff --git a/testes/db.lua b/testes/db.lua new file mode 100644 index 00000000..004f57a7 --- /dev/null +++ b/testes/db.lua | |||
@@ -0,0 +1,857 @@ | |||
1 | -- $Id: db.lua,v 1.79 2016/11/07 13:02:34 roberto Exp $ | ||
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 | 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 debug.getinfo(1000)) -- out of range level | ||
35 | assert(not debug.getinfo(-1)) -- out of range level | ||
36 | local a = debug.getinfo(print) | ||
37 | assert(a.what == "C" and a.short_src == "[C]") | ||
38 | a = debug.getinfo(print, "L") | ||
39 | assert(a.activelines == nil) | ||
40 | local b = debug.getinfo(test, "SfL") | ||
41 | assert(b.name == nil and b.what == "Lua" and b.linedefined == testline and | ||
42 | b.lastlinedefined == b.linedefined + 10 and | ||
43 | b.func == test and not string.find(b.short_src, "%[")) | ||
44 | assert(b.activelines[b.linedefined + 1] and | ||
45 | b.activelines[b.lastlinedefined]) | ||
46 | assert(not b.activelines[b.linedefined] and | ||
47 | not b.activelines[b.lastlinedefined + 1]) | ||
48 | end | ||
49 | |||
50 | |||
51 | -- test file and string names truncation | ||
52 | a = "function f () end" | ||
53 | local function dostring (s, x) return load(s, x)() end | ||
54 | dostring(a) | ||
55 | assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a)) | ||
56 | dostring(a..string.format("; %s\n=1", string.rep('p', 400))) | ||
57 | assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$')) | ||
58 | dostring(a..string.format("; %s=1", string.rep('p', 400))) | ||
59 | assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$')) | ||
60 | dostring("\n"..a) | ||
61 | assert(debug.getinfo(f).short_src == '[string "..."]') | ||
62 | dostring(a, "") | ||
63 | assert(debug.getinfo(f).short_src == '[string ""]') | ||
64 | dostring(a, "@xuxu") | ||
65 | assert(debug.getinfo(f).short_src == "xuxu") | ||
66 | dostring(a, "@"..string.rep('p', 1000)..'t') | ||
67 | assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$")) | ||
68 | dostring(a, "=xuxu") | ||
69 | assert(debug.getinfo(f).short_src == "xuxu") | ||
70 | dostring(a, string.format("=%s", string.rep('x', 500))) | ||
71 | assert(string.find(debug.getinfo(f).short_src, "^x*$")) | ||
72 | dostring(a, "=") | ||
73 | assert(debug.getinfo(f).short_src == "") | ||
74 | a = nil; f = nil; | ||
75 | |||
76 | |||
77 | repeat | ||
78 | local g = {x = function () | ||
79 | local a = debug.getinfo(2) | ||
80 | assert(a.name == 'f' and a.namewhat == 'local') | ||
81 | a = debug.getinfo(1) | ||
82 | assert(a.name == 'x' and a.namewhat == 'field') | ||
83 | return 'xixi' | ||
84 | end} | ||
85 | local f = function () return 1+1 and (not 1 or g.x()) end | ||
86 | assert(f() == 'xixi') | ||
87 | g = debug.getinfo(f) | ||
88 | assert(g.what == "Lua" and g.func == f and g.namewhat == "" and not g.name) | ||
89 | |||
90 | function f (x, name) -- local! | ||
91 | name = name or 'f' | ||
92 | local a = debug.getinfo(1) | ||
93 | assert(a.name == name and a.namewhat == 'local') | ||
94 | return x | ||
95 | end | ||
96 | |||
97 | -- breaks in different conditions | ||
98 | if 3>4 then break end; f() | ||
99 | if 3<4 then a=1 else break end; f() | ||
100 | while 1 do local x=10; break end; f() | ||
101 | local b = 1 | ||
102 | if 3>4 then return math.sin(1) end; f() | ||
103 | a = 3<4; f() | ||
104 | a = 3<4 or 1; f() | ||
105 | repeat local x=20; if 4>3 then f() else break end; f() until 1 | ||
106 | g = {} | ||
107 | f(g).x = f(2) and f(10)+f(9) | ||
108 | assert(g.x == f(19)) | ||
109 | function g(x) if not x then return 3 end return (x('a', 'x')) end | ||
110 | assert(g(f) == 'a') | ||
111 | until 1 | ||
112 | |||
113 | test([[if | ||
114 | math.sin(1) | ||
115 | then | ||
116 | a=1 | ||
117 | else | ||
118 | a=2 | ||
119 | end | ||
120 | ]], {2,3,4,7}) | ||
121 | |||
122 | test([[-- | ||
123 | if nil then | ||
124 | a=1 | ||
125 | else | ||
126 | a=2 | ||
127 | end | ||
128 | ]], {2,5,6}) | ||
129 | |||
130 | test([[a=1 | ||
131 | repeat | ||
132 | a=a+1 | ||
133 | until a==3 | ||
134 | ]], {1,3,4,3,4}) | ||
135 | |||
136 | test([[ do | ||
137 | return | ||
138 | end | ||
139 | ]], {2}) | ||
140 | |||
141 | test([[local a | ||
142 | a=1 | ||
143 | while a<=3 do | ||
144 | a=a+1 | ||
145 | end | ||
146 | ]], {1,2,3,4,3,4,3,4,3,5}) | ||
147 | |||
148 | test([[while math.sin(1) do | ||
149 | if math.sin(1) | ||
150 | then break | ||
151 | end | ||
152 | end | ||
153 | a=1]], {1,2,3,6}) | ||
154 | |||
155 | test([[for i=1,3 do | ||
156 | a=i | ||
157 | end | ||
158 | ]], {1,2,1,2,1,2,1,3}) | ||
159 | |||
160 | test([[for i,v in pairs{'a','b'} do | ||
161 | a=tostring(i) .. v | ||
162 | end | ||
163 | ]], {1,2,1,2,1,3}) | ||
164 | |||
165 | test([[for i=1,4 do a=1 end]], {1,1,1,1,1}) | ||
166 | |||
167 | |||
168 | |||
169 | print'+' | ||
170 | |||
171 | -- invalid levels in [gs]etlocal | ||
172 | assert(not pcall(debug.getlocal, 20, 1)) | ||
173 | assert(not pcall(debug.setlocal, -1, 1, 10)) | ||
174 | |||
175 | |||
176 | -- parameter names | ||
177 | local function foo (a,b,...) local d, e end | ||
178 | local co = coroutine.create(foo) | ||
179 | |||
180 | assert(debug.getlocal(foo, 1) == 'a') | ||
181 | assert(debug.getlocal(foo, 2) == 'b') | ||
182 | assert(not debug.getlocal(foo, 3)) | ||
183 | assert(debug.getlocal(co, foo, 1) == 'a') | ||
184 | assert(debug.getlocal(co, foo, 2) == 'b') | ||
185 | assert(not debug.getlocal(co, foo, 3)) | ||
186 | |||
187 | assert(not debug.getlocal(print, 1)) | ||
188 | |||
189 | |||
190 | -- varargs | ||
191 | local function foo (a, ...) | ||
192 | local t = table.pack(...) | ||
193 | for i = 1, t.n do | ||
194 | local n, v = debug.getlocal(1, -i) | ||
195 | assert(n == "(*vararg)" and v == t[i]) | ||
196 | end | ||
197 | assert(not debug.getlocal(1, -(t.n + 1))) | ||
198 | assert(not debug.setlocal(1, -(t.n + 1), 30)) | ||
199 | if t.n > 0 then | ||
200 | (function (x) | ||
201 | assert(debug.setlocal(2, -1, x) == "(*vararg)") | ||
202 | assert(debug.setlocal(2, -t.n, x) == "(*vararg)") | ||
203 | end)(430) | ||
204 | assert(... == 430) | ||
205 | end | ||
206 | end | ||
207 | |||
208 | foo() | ||
209 | foo(print) | ||
210 | foo(200, 3, 4) | ||
211 | local a = {} | ||
212 | for i = 1, (_soft and 100 or 1000) do a[i] = i end | ||
213 | foo(table.unpack(a)) | ||
214 | a = nil | ||
215 | |||
216 | -- access to vararg in non-vararg function | ||
217 | local function foo () return debug.getlocal(1, -1) end | ||
218 | assert(not foo(10)) | ||
219 | |||
220 | |||
221 | do -- test hook presence in debug info | ||
222 | assert(not debug.gethook()) | ||
223 | local count = 0 | ||
224 | local function f () | ||
225 | assert(debug.getinfo(1).namewhat == "hook") | ||
226 | local sndline = string.match(debug.traceback(), "\n(.-)\n") | ||
227 | assert(string.find(sndline, "hook")) | ||
228 | count = count + 1 | ||
229 | end | ||
230 | debug.sethook(f, "l") | ||
231 | local a = 0 | ||
232 | _ENV.a = a | ||
233 | a = 1 | ||
234 | debug.sethook() | ||
235 | assert(count == 4) | ||
236 | end | ||
237 | |||
238 | |||
239 | a = {}; L = nil | ||
240 | local glob = 1 | ||
241 | local oldglob = glob | ||
242 | debug.sethook(function (e,l) | ||
243 | collectgarbage() -- force GC during a hook | ||
244 | local f, m, c = debug.gethook() | ||
245 | assert(m == 'crl' and c == 0) | ||
246 | if e == "line" then | ||
247 | if glob ~= oldglob then | ||
248 | L = l-1 -- get the first line where "glob" has changed | ||
249 | oldglob = glob | ||
250 | end | ||
251 | elseif e == "call" then | ||
252 | local f = debug.getinfo(2, "f").func | ||
253 | a[f] = 1 | ||
254 | else assert(e == "return") | ||
255 | end | ||
256 | end, "crl") | ||
257 | |||
258 | |||
259 | function f(a,b) | ||
260 | collectgarbage() | ||
261 | local _, x = debug.getlocal(1, 1) | ||
262 | local _, y = debug.getlocal(1, 2) | ||
263 | assert(x == a and y == b) | ||
264 | assert(debug.setlocal(2, 3, "pera") == "AA".."AA") | ||
265 | assert(debug.setlocal(2, 4, "maçã") == "B") | ||
266 | x = debug.getinfo(2) | ||
267 | assert(x.func == g and x.what == "Lua" and x.name == 'g' and | ||
268 | x.nups == 2 and string.find(x.source, "^@.*db%.lua$")) | ||
269 | glob = glob+1 | ||
270 | assert(debug.getinfo(1, "l").currentline == L+1) | ||
271 | assert(debug.getinfo(1, "l").currentline == L+2) | ||
272 | end | ||
273 | |||
274 | function foo() | ||
275 | glob = glob+1 | ||
276 | assert(debug.getinfo(1, "l").currentline == L+1) | ||
277 | end; foo() -- set L | ||
278 | -- check line counting inside strings and empty lines | ||
279 | |||
280 | _ = 'alo\ | ||
281 | alo' .. [[ | ||
282 | |||
283 | ]] | ||
284 | --[[ | ||
285 | ]] | ||
286 | assert(debug.getinfo(1, "l").currentline == L+11) -- check count of lines | ||
287 | |||
288 | |||
289 | function g(...) | ||
290 | local arg = {...} | ||
291 | do local a,b,c; a=math.sin(40); end | ||
292 | local feijao | ||
293 | local AAAA,B = "xuxu", "mamão" | ||
294 | f(AAAA,B) | ||
295 | assert(AAAA == "pera" and B == "maçã") | ||
296 | do | ||
297 | local B = 13 | ||
298 | local x,y = debug.getlocal(1,5) | ||
299 | assert(x == 'B' and y == 13) | ||
300 | end | ||
301 | end | ||
302 | |||
303 | g() | ||
304 | |||
305 | |||
306 | assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print]) | ||
307 | |||
308 | |||
309 | -- tests for manipulating non-registered locals (C and Lua temporaries) | ||
310 | |||
311 | local n, v = debug.getlocal(0, 1) | ||
312 | assert(v == 0 and n == "(*temporary)") | ||
313 | local n, v = debug.getlocal(0, 2) | ||
314 | assert(v == 2 and n == "(*temporary)") | ||
315 | assert(not debug.getlocal(0, 3)) | ||
316 | assert(not debug.getlocal(0, 0)) | ||
317 | |||
318 | function f() | ||
319 | assert(select(2, debug.getlocal(2,3)) == 1) | ||
320 | assert(not debug.getlocal(2,4)) | ||
321 | debug.setlocal(2, 3, 10) | ||
322 | return 20 | ||
323 | end | ||
324 | |||
325 | function g(a,b) return (a+1) + f() end | ||
326 | |||
327 | assert(g(0,0) == 30) | ||
328 | |||
329 | |||
330 | debug.sethook(nil); | ||
331 | assert(debug.gethook() == nil) | ||
332 | |||
333 | |||
334 | -- testing access to function arguments | ||
335 | |||
336 | local function collectlocals (level) | ||
337 | local tab = {} | ||
338 | for i = 1, math.huge do | ||
339 | local n, v = debug.getlocal(level + 1, i) | ||
340 | if not (n and string.find(n, "^[a-zA-Z0-9_]+$")) then | ||
341 | break -- consider only real variables | ||
342 | end | ||
343 | tab[n] = v | ||
344 | end | ||
345 | return tab | ||
346 | end | ||
347 | |||
348 | |||
349 | X = nil | ||
350 | a = {} | ||
351 | function a:f (a, b, ...) local arg = {...}; local c = 13 end | ||
352 | debug.sethook(function (e) | ||
353 | assert(e == "call") | ||
354 | dostring("XX = 12") -- test dostring inside hooks | ||
355 | -- testing errors inside hooks | ||
356 | assert(not pcall(load("a='joao'+1"))) | ||
357 | debug.sethook(function (e, l) | ||
358 | assert(debug.getinfo(2, "l").currentline == l) | ||
359 | local f,m,c = debug.gethook() | ||
360 | assert(e == "line") | ||
361 | assert(m == 'l' and c == 0) | ||
362 | debug.sethook(nil) -- hook is called only once | ||
363 | assert(not X) -- check that | ||
364 | X = collectlocals(2) | ||
365 | end, "l") | ||
366 | end, "c") | ||
367 | |||
368 | a:f(1,2,3,4,5) | ||
369 | assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil) | ||
370 | assert(XX == 12) | ||
371 | assert(debug.gethook() == nil) | ||
372 | |||
373 | |||
374 | -- testing access to local variables in return hook (bug in 5.2) | ||
375 | do | ||
376 | local function foo (a, b) | ||
377 | do local x,y,z end | ||
378 | local c, d = 10, 20 | ||
379 | return | ||
380 | end | ||
381 | |||
382 | local function aux () | ||
383 | if debug.getinfo(2).name == "foo" then | ||
384 | foo = nil -- to signal that it found 'foo' | ||
385 | local tab = {a = 100, b = 200, c = 10, d = 20} | ||
386 | for n, v in pairs(collectlocals(2)) do | ||
387 | assert(tab[n] == v) | ||
388 | tab[n] = nil | ||
389 | end | ||
390 | assert(next(tab) == nil) -- 'tab' must be empty | ||
391 | end | ||
392 | end | ||
393 | |||
394 | debug.sethook(aux, "r"); foo(100, 200); debug.sethook() | ||
395 | assert(foo == nil) | ||
396 | end | ||
397 | |||
398 | -- testing upvalue access | ||
399 | local function getupvalues (f) | ||
400 | local t = {} | ||
401 | local i = 1 | ||
402 | while true do | ||
403 | local name, value = debug.getupvalue(f, i) | ||
404 | if not name then break end | ||
405 | assert(not t[name]) | ||
406 | t[name] = value | ||
407 | i = i + 1 | ||
408 | end | ||
409 | return t | ||
410 | end | ||
411 | |||
412 | local a,b,c = 1,2,3 | ||
413 | local function foo1 (a) b = a; return c end | ||
414 | local function foo2 (x) a = x; return c+b end | ||
415 | assert(not debug.getupvalue(foo1, 3)) | ||
416 | assert(not debug.getupvalue(foo1, 0)) | ||
417 | assert(not debug.setupvalue(foo1, 3, "xuxu")) | ||
418 | local t = getupvalues(foo1) | ||
419 | assert(t.a == nil and t.b == 2 and t.c == 3) | ||
420 | t = getupvalues(foo2) | ||
421 | assert(t.a == 1 and t.b == 2 and t.c == 3) | ||
422 | assert(debug.setupvalue(foo1, 1, "xuxu") == "b") | ||
423 | assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu") | ||
424 | -- upvalues of C functions are allways "called" "" (the empty string) | ||
425 | assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "") | ||
426 | |||
427 | |||
428 | -- testing count hooks | ||
429 | local a=0 | ||
430 | debug.sethook(function (e) a=a+1 end, "", 1) | ||
431 | a=0; for i=1,1000 do end; assert(1000 < a and a < 1012) | ||
432 | debug.sethook(function (e) a=a+1 end, "", 4) | ||
433 | a=0; for i=1,1000 do end; assert(250 < a and a < 255) | ||
434 | local f,m,c = debug.gethook() | ||
435 | assert(m == "" and c == 4) | ||
436 | debug.sethook(function (e) a=a+1 end, "", 4000) | ||
437 | a=0; for i=1,1000 do end; assert(a == 0) | ||
438 | |||
439 | do | ||
440 | debug.sethook(print, "", 2^24 - 1) -- count upperbound | ||
441 | local f,m,c = debug.gethook() | ||
442 | assert(({debug.gethook()})[3] == 2^24 - 1) | ||
443 | end | ||
444 | |||
445 | debug.sethook() | ||
446 | |||
447 | |||
448 | -- tests for tail calls | ||
449 | local function f (x) | ||
450 | if x then | ||
451 | assert(debug.getinfo(1, "S").what == "Lua") | ||
452 | assert(debug.getinfo(1, "t").istailcall == true) | ||
453 | local tail = debug.getinfo(2) | ||
454 | assert(tail.func == g1 and tail.istailcall == true) | ||
455 | assert(debug.getinfo(3, "S").what == "main") | ||
456 | print"+" | ||
457 | end | ||
458 | end | ||
459 | |||
460 | function g(x) return f(x) end | ||
461 | |||
462 | function g1(x) g(x) end | ||
463 | |||
464 | local function h (x) local f=g1; return f(x) end | ||
465 | |||
466 | h(true) | ||
467 | |||
468 | local b = {} | ||
469 | debug.sethook(function (e) table.insert(b, e) end, "cr") | ||
470 | h(false) | ||
471 | debug.sethook() | ||
472 | local res = {"return", -- first return (from sethook) | ||
473 | "call", "tail call", "call", "tail call", | ||
474 | "return", "return", | ||
475 | "call", -- last call (to sethook) | ||
476 | } | ||
477 | for i = 1, #res do assert(res[i] == table.remove(b, 1)) end | ||
478 | |||
479 | b = 0 | ||
480 | debug.sethook(function (e) | ||
481 | if e == "tail call" then | ||
482 | b = b + 1 | ||
483 | assert(debug.getinfo(2, "t").istailcall == true) | ||
484 | else | ||
485 | assert(debug.getinfo(2, "t").istailcall == false) | ||
486 | end | ||
487 | end, "c") | ||
488 | h(false) | ||
489 | debug.sethook() | ||
490 | assert(b == 2) -- two tail calls | ||
491 | |||
492 | lim = _soft and 3000 or 30000 | ||
493 | local function foo (x) | ||
494 | if x==0 then | ||
495 | assert(debug.getinfo(2).what == "main") | ||
496 | local info = debug.getinfo(1) | ||
497 | assert(info.istailcall == true and info.func == foo) | ||
498 | else return foo(x-1) | ||
499 | end | ||
500 | end | ||
501 | |||
502 | foo(lim) | ||
503 | |||
504 | |||
505 | print"+" | ||
506 | |||
507 | |||
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 | assert(type(debug.getregistry()) == "table") | ||
683 | |||
684 | |||
685 | -- test tagmethod information | ||
686 | local a = {} | ||
687 | local function f (t) | ||
688 | local info = debug.getinfo(1); | ||
689 | assert(info.namewhat == "metamethod") | ||
690 | a.op = info.name | ||
691 | return info.name | ||
692 | end | ||
693 | setmetatable(a, { | ||
694 | __index = f; __add = f; __div = f; __mod = f; __concat = f; __pow = f; | ||
695 | __mul = f; __idiv = f; __unm = f; __len = f; __sub = f; | ||
696 | __shl = f; __shr = f; __bor = f; __bxor = f; | ||
697 | __eq = f; __le = f; __lt = f; __unm = f; __len = f; __band = f; | ||
698 | __bnot = f; | ||
699 | }) | ||
700 | |||
701 | local b = setmetatable({}, getmetatable(a)) | ||
702 | |||
703 | assert(a[3] == "__index" and a^3 == "__pow" and a..a == "__concat") | ||
704 | assert(a/3 == "__div" and 3%a == "__mod") | ||
705 | assert(a+3 == "__add" and 3-a == "__sub" and a*3 == "__mul" and | ||
706 | -a == "__unm" and #a == "__len" and a&3 == "__band") | ||
707 | assert(a|3 == "__bor" and 3~a == "__bxor" and a<<3 == "__shl" and | ||
708 | a>>1 == "__shr") | ||
709 | assert (a==b and a.op == "__eq") | ||
710 | assert (a>=b and a.op == "__le") | ||
711 | assert (a>b and a.op == "__lt") | ||
712 | assert(~a == "__bnot") | ||
713 | |||
714 | do -- testing for-iterator name | ||
715 | local function f() | ||
716 | assert(debug.getinfo(1).name == "for iterator") | ||
717 | end | ||
718 | |||
719 | for i in f do end | ||
720 | end | ||
721 | |||
722 | |||
723 | do -- testing debug info for finalizers | ||
724 | local name = nil | ||
725 | |||
726 | -- create a piece of garbage with a finalizer | ||
727 | setmetatable({}, {__gc = function () | ||
728 | local t = debug.getinfo(2) -- get callee information | ||
729 | assert(t.namewhat == "metamethod") | ||
730 | name = t.name | ||
731 | end}) | ||
732 | |||
733 | -- repeat until previous finalizer runs (setting 'name') | ||
734 | repeat local a = {} until name | ||
735 | assert(name == "__gc") | ||
736 | end | ||
737 | |||
738 | |||
739 | do | ||
740 | print("testing traceback sizes") | ||
741 | |||
742 | local function countlines (s) | ||
743 | return select(2, string.gsub(s, "\n", "")) | ||
744 | end | ||
745 | |||
746 | local function deep (lvl, n) | ||
747 | if lvl == 0 then | ||
748 | return (debug.traceback("message", n)) | ||
749 | else | ||
750 | return (deep(lvl-1, n)) | ||
751 | end | ||
752 | end | ||
753 | |||
754 | local function checkdeep (total, start) | ||
755 | local s = deep(total, start) | ||
756 | local rest = string.match(s, "^message\nstack traceback:\n(.*)$") | ||
757 | local cl = countlines(rest) | ||
758 | -- at most 10 lines in first part, 11 in second, plus '...' | ||
759 | assert(cl <= 10 + 11 + 1) | ||
760 | local brk = string.find(rest, "%.%.%.") | ||
761 | if brk then -- does message have '...'? | ||
762 | local rest1 = string.sub(rest, 1, brk) | ||
763 | local rest2 = string.sub(rest, brk, #rest) | ||
764 | assert(countlines(rest1) == 10 and countlines(rest2) == 11) | ||
765 | else | ||
766 | assert(cl == total - start + 2) | ||
767 | end | ||
768 | end | ||
769 | |||
770 | for d = 1, 51, 10 do | ||
771 | for l = 1, d do | ||
772 | -- use coroutines to ensure complete control of the stack | ||
773 | coroutine.wrap(checkdeep)(d, l) | ||
774 | end | ||
775 | end | ||
776 | |||
777 | end | ||
778 | |||
779 | |||
780 | print("testing debug functions on chunk without debug info") | ||
781 | prog = [[-- program to be loaded without debug information | ||
782 | local debug = require'debug' | ||
783 | local a = 12 -- a local variable | ||
784 | |||
785 | local n, v = debug.getlocal(1, 1) | ||
786 | assert(n == "(*temporary)" and v == debug) -- unkown name but known value | ||
787 | n, v = debug.getlocal(1, 2) | ||
788 | assert(n == "(*temporary)" and v == 12) -- unkown name but known value | ||
789 | |||
790 | -- a function with an upvalue | ||
791 | local f = function () local x; return a end | ||
792 | n, v = debug.getupvalue(f, 1) | ||
793 | assert(n == "(*no name)" and v == 12) | ||
794 | assert(debug.setupvalue(f, 1, 13) == "(*no name)") | ||
795 | assert(a == 13) | ||
796 | |||
797 | local t = debug.getinfo(f) | ||
798 | assert(t.name == nil and t.linedefined > 0 and | ||
799 | t.lastlinedefined == t.linedefined and | ||
800 | t.short_src == "?") | ||
801 | assert(debug.getinfo(1).currentline == -1) | ||
802 | |||
803 | t = debug.getinfo(f, "L").activelines | ||
804 | assert(next(t) == nil) -- active lines are empty | ||
805 | |||
806 | -- dump/load a function without debug info | ||
807 | f = load(string.dump(f)) | ||
808 | |||
809 | t = debug.getinfo(f) | ||
810 | assert(t.name == nil and t.linedefined > 0 and | ||
811 | t.lastlinedefined == t.linedefined and | ||
812 | t.short_src == "?") | ||
813 | assert(debug.getinfo(1).currentline == -1) | ||
814 | |||
815 | return a | ||
816 | ]] | ||
817 | |||
818 | |||
819 | -- load 'prog' without debug info | ||
820 | local f = assert(load(string.dump(load(prog), true))) | ||
821 | |||
822 | assert(f() == 13) | ||
823 | |||
824 | do -- tests for 'source' in binary dumps | ||
825 | local prog = [[ | ||
826 | return function (x) | ||
827 | return function (y) | ||
828 | return x + y | ||
829 | end | ||
830 | end | ||
831 | ]] | ||
832 | local name = string.rep("x", 1000) | ||
833 | local p = assert(load(prog, name)) | ||
834 | -- load 'p' as a binary chunk with debug information | ||
835 | local c = string.dump(p) | ||
836 | assert(#c > 1000 and #c < 2000) -- no repetition of 'source' in dump | ||
837 | local f = assert(load(c)) | ||
838 | local g = f() | ||
839 | local h = g(3) | ||
840 | assert(h(5) == 8) | ||
841 | assert(debug.getinfo(f).source == name and -- all functions have 'source' | ||
842 | debug.getinfo(g).source == name and | ||
843 | debug.getinfo(h).source == name) | ||
844 | -- again, without debug info | ||
845 | local c = string.dump(p, true) | ||
846 | assert(#c < 500) -- no 'source' in dump | ||
847 | local f = assert(load(c)) | ||
848 | local g = f() | ||
849 | local h = g(30) | ||
850 | assert(h(50) == 80) | ||
851 | assert(debug.getinfo(f).source == '=?' and -- no function has 'source' | ||
852 | debug.getinfo(g).source == '=?' and | ||
853 | debug.getinfo(h).source == '=?') | ||
854 | end | ||
855 | |||
856 | print"OK" | ||
857 | |||