diff options
Diffstat (limited to '')
| -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 | |||
