github.com/xmx/lua@v0.0.0-20230324063450-8a298e091302/_lua5.1-tests/db.lua (about) 1 -- testing debug library 2 3 local function dostring(s) return assert(loadstring(s))() end 4 5 print"testing debug library and debug information" 6 7 do 8 local a=1 9 end 10 11 function test (s, l, p) 12 collectgarbage() -- avoid gc during trace 13 local function f (event, line) 14 assert(event == 'line') 15 local l = table.remove(l, 1) 16 if p then print(l, line) end 17 assert(l == line, "wrong trace!!") 18 end 19 debug.sethook(f,"l"); loadstring(s)(); debug.sethook() 20 assert(table.getn(l) == 0) 21 end 22 23 24 do 25 local a = debug.getinfo(print) 26 assert(a.what == "C" and a.short_src == "[C]") 27 local b = debug.getinfo(test, "SfL") 28 assert(b.name == nil and b.what == "Lua" and b.linedefined == 11 and 29 b.lastlinedefined == b.linedefined + 10 and 30 b.func == test and not string.find(b.short_src, "%[")) 31 assert(b.activelines[b.linedefined + 1] and 32 b.activelines[b.lastlinedefined]) 33 assert(not b.activelines[b.linedefined] and 34 not b.activelines[b.lastlinedefined + 1]) 35 end 36 37 38 -- test file and string names truncation 39 a = "function f () end" 40 local function dostring (s, x) return loadstring(s, x)() end 41 dostring(a) 42 assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a)) 43 dostring(a..string.format("; %s\n=1", string.rep('p', 400))) 44 assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$')) 45 dostring("\n"..a) 46 assert(debug.getinfo(f).short_src == '[string "..."]') 47 dostring(a, "") 48 assert(debug.getinfo(f).short_src == '[string ""]') 49 dostring(a, "@xuxu") 50 assert(debug.getinfo(f).short_src == "xuxu") 51 dostring(a, "@"..string.rep('p', 1000)..'t') 52 assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$")) 53 dostring(a, "=xuxu") 54 assert(debug.getinfo(f).short_src == "xuxu") 55 dostring(a, string.format("=%s", string.rep('x', 500))) 56 assert(string.find(debug.getinfo(f).short_src, "^x*")) 57 dostring(a, "=") 58 assert(debug.getinfo(f).short_src == "") 59 a = nil; f = nil; 60 61 62 repeat 63 local g = {x = function () 64 local a = debug.getinfo(2) 65 assert(a.name == 'f' and a.namewhat == 'local') 66 a = debug.getinfo(1) 67 assert(a.name == 'x' and a.namewhat == 'field') 68 return 'xixi' 69 end} 70 local f = function () return 1+1 and (not 1 or g.x()) end 71 assert(f() == 'xixi') 72 g = debug.getinfo(f) 73 assert(g.what == "Lua" and g.func == f and g.namewhat == "" and not g.name) 74 75 function f (x, name) -- local! 76 name = name or 'f' 77 local a = debug.getinfo(1) 78 assert(a.name == name and a.namewhat == 'local') 79 return x 80 end 81 82 -- breaks in different conditions 83 if 3>4 then break end; f() 84 if 3<4 then a=1 else break end; f() 85 while 1 do local x=10; break end; f() 86 local b = 1 87 if 3>4 then return math.sin(1) end; f() 88 a = 3<4; f() 89 a = 3<4 or 1; f() 90 repeat local x=20; if 4>3 then f() else break end; f() until 1 91 g = {} 92 f(g).x = f(2) and f(10)+f(9) 93 assert(g.x == f(19)) 94 function g(x) if not x then return 3 end return (x('a', 'x')) end 95 assert(g(f) == 'a') 96 until 1 97 98 test([[if 99 math.sin(1) 100 then 101 a=1 102 else 103 a=2 104 end 105 ]], {2,4,7}) 106 107 test([[-- 108 if nil then 109 a=1 110 else 111 a=2 112 end 113 ]], {2,5,6}) 114 115 test([[a=1 116 repeat 117 a=a+1 118 until a==3 119 ]], {1,3,4,3,4}) 120 121 test([[ do 122 return 123 end 124 ]], {2}) 125 126 test([[local a 127 a=1 128 while a<=3 do 129 a=a+1 130 end 131 ]], {2,3,4,3,4,3,4,3,5}) 132 133 test([[while math.sin(1) do 134 if math.sin(1) 135 then 136 break 137 end 138 end 139 a=1]], {1,2,4,7}) 140 141 test([[for i=1,3 do 142 a=i 143 end 144 ]], {1,2,1,2,1,2,1,3}) 145 146 test([[for i,v in pairs{'a','b'} do 147 a=i..v 148 end 149 ]], {1,2,1,2,1,3}) 150 151 test([[for i=1,4 do a=1 end]], {1,1,1,1,1}) 152 153 154 155 print'+' 156 157 a = {}; L = nil 158 local glob = 1 159 local oldglob = glob 160 debug.sethook(function (e,l) 161 collectgarbage() -- force GC during a hook 162 local f, m, c = debug.gethook() 163 assert(m == 'crl' and c == 0) 164 if e == "line" then 165 if glob ~= oldglob then 166 L = l-1 -- get the first line where "glob" has changed 167 oldglob = glob 168 end 169 elseif e == "call" then 170 local f = debug.getinfo(2, "f").func 171 a[f] = 1 172 else assert(e == "return") 173 end 174 end, "crl") 175 176 function f(a,b) 177 collectgarbage() 178 local _, x = debug.getlocal(1, 1) 179 local _, y = debug.getlocal(1, 2) 180 assert(x == a and y == b) 181 assert(debug.setlocal(2, 3, "pera") == "AA".."AA") 182 assert(debug.setlocal(2, 4, "maçã") == "B") 183 x = debug.getinfo(2) 184 assert(x.func == g and x.what == "Lua" and x.name == 'g' and 185 x.nups == 0 and string.find(x.source, "^@.*db%.lua")) 186 glob = glob+1 187 assert(debug.getinfo(1, "l").currentline == L+1) 188 assert(debug.getinfo(1, "l").currentline == L+2) 189 end 190 191 function foo() 192 glob = glob+1 193 assert(debug.getinfo(1, "l").currentline == L+1) 194 end; foo() -- set L 195 -- check line counting inside strings and empty lines 196 197 _ = 'alo\ 198 alo' .. [[ 199 200 ]] 201 --[[ 202 ]] 203 assert(debug.getinfo(1, "l").currentline == L+11) -- check count of lines 204 205 206 function g(...) 207 do local a,b,c; a=math.sin(40); end 208 local feijao 209 local AAAA,B = "xuxu", "mamão" 210 f(AAAA,B) 211 assert(AAAA == "pera" and B == "maçã") 212 do 213 local B = 13 214 local x,y = debug.getlocal(1,5) 215 assert(x == 'B' and y == 13) 216 end 217 end 218 219 g() 220 221 222 assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print]) 223 224 225 -- tests for manipulating non-registered locals (C and Lua temporaries) 226 227 local n, v = debug.getlocal(0, 1) 228 assert(v == 0 and n == "(*temporary)") 229 local n, v = debug.getlocal(0, 2) 230 assert(v == 2 and n == "(*temporary)") 231 assert(not debug.getlocal(0, 3)) 232 assert(not debug.getlocal(0, 0)) 233 234 function f() 235 assert(select(2, debug.getlocal(2,3)) == 1) 236 assert(not debug.getlocal(2,4)) 237 debug.setlocal(2, 3, 10) 238 return 20 239 end 240 241 function g(a,b) return (a+1) + f() end 242 243 assert(g(0,0) == 30) 244 245 246 debug.sethook(nil); 247 assert(debug.gethook() == nil) 248 249 250 -- testing access to function arguments 251 252 X = nil 253 a = {} 254 function a:f (a, b, ...) local c = 13 end 255 debug.sethook(function (e) 256 assert(e == "call") 257 dostring("XX = 12") -- test dostring inside hooks 258 -- testing errors inside hooks 259 assert(not pcall(loadstring("a='joao'+1"))) 260 debug.sethook(function (e, l) 261 assert(debug.getinfo(2, "l").currentline == l) 262 local f,m,c = debug.gethook() 263 assert(e == "line") 264 assert(m == 'l' and c == 0) 265 debug.sethook(nil) -- hook is called only once 266 assert(not X) -- check that 267 X = {}; local i = 1 268 local x,y 269 while 1 do 270 x,y = debug.getlocal(2, i) 271 if x==nil then break end 272 X[x] = y 273 i = i+1 274 end 275 end, "l") 276 end, "c") 277 278 a:f(1,2,3,4,5) 279 assert(X.self == a and X.a == 1 and X.b == 2 and X.arg.n == 3 and X.c == nil) 280 assert(XX == 12) 281 assert(debug.gethook() == nil) 282 283 284 -- testing upvalue access 285 local function getupvalues (f) 286 local t = {} 287 local i = 1 288 while true do 289 local name, value = debug.getupvalue(f, i) 290 if not name then break end 291 assert(not t[name]) 292 t[name] = value 293 i = i + 1 294 end 295 return t 296 end 297 298 local a,b,c = 1,2,3 299 local function foo1 (a) b = a; return c end 300 local function foo2 (x) a = x; return c+b end 301 assert(debug.getupvalue(foo1, 3) == nil) 302 assert(debug.getupvalue(foo1, 0) == nil) 303 assert(debug.setupvalue(foo1, 3, "xuxu") == nil) 304 local t = getupvalues(foo1) 305 assert(t.a == nil and t.b == 2 and t.c == 3) 306 t = getupvalues(foo2) 307 assert(t.a == 1 and t.b == 2 and t.c == 3) 308 assert(debug.setupvalue(foo1, 1, "xuxu") == "b") 309 assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu") 310 -- cannot manipulate C upvalues from Lua 311 assert(debug.getupvalue(io.read, 1) == nil) 312 assert(debug.setupvalue(io.read, 1, 10) == nil) 313 314 315 -- testing count hooks 316 local a=0 317 debug.sethook(function (e) a=a+1 end, "", 1) 318 a=0; for i=1,1000 do end; assert(1000 < a and a < 1012) 319 debug.sethook(function (e) a=a+1 end, "", 4) 320 a=0; for i=1,1000 do end; assert(250 < a and a < 255) 321 local f,m,c = debug.gethook() 322 assert(m == "" and c == 4) 323 debug.sethook(function (e) a=a+1 end, "", 4000) 324 a=0; for i=1,1000 do end; assert(a == 0) 325 debug.sethook(print, "", 2^24 - 1) -- count upperbound 326 local f,m,c = debug.gethook() 327 assert(({debug.gethook()})[3] == 2^24 - 1) 328 debug.sethook() 329 330 331 -- tests for tail calls 332 local function f (x) 333 if x then 334 assert(debug.getinfo(1, "S").what == "Lua") 335 local tail = debug.getinfo(2) 336 assert(not pcall(getfenv, 3)) 337 assert(tail.what == "tail" and tail.short_src == "(tail call)" and 338 tail.linedefined == -1 and tail.func == nil) 339 assert(debug.getinfo(3, "f").func == g1) 340 assert(getfenv(3)) 341 assert(debug.getinfo(4, "S").what == "tail") 342 assert(not pcall(getfenv, 5)) 343 assert(debug.getinfo(5, "S").what == "main") 344 assert(getfenv(5)) 345 print"+" 346 end 347 end 348 349 function g(x) return f(x) end 350 351 function g1(x) g(x) end 352 353 local function h (x) local f=g1; return f(x) end 354 355 h(true) 356 357 local b = {} 358 debug.sethook(function (e) table.insert(b, e) end, "cr") 359 h(false) 360 debug.sethook() 361 local res = {"return", -- first return (from sethook) 362 "call", "call", "call", "call", 363 "return", "tail return", "return", "tail return", 364 "call", -- last call (to sethook) 365 } 366 for _, k in ipairs(res) do assert(k == table.remove(b, 1)) end 367 368 369 lim = 30000 370 local function foo (x) 371 if x==0 then 372 assert(debug.getinfo(lim+2).what == "main") 373 for i=2,lim do assert(debug.getinfo(i, "S").what == "tail") end 374 else return foo(x-1) 375 end 376 end 377 378 foo(lim) 379 380 381 print"+" 382 383 384 -- testing traceback 385 386 assert(debug.traceback(print) == print) 387 assert(debug.traceback(print, 4) == print) 388 assert(string.find(debug.traceback("hi", 4), "^hi\n")) 389 assert(string.find(debug.traceback("hi"), "^hi\n")) 390 assert(not string.find(debug.traceback("hi"), "'traceback'")) 391 assert(string.find(debug.traceback("hi", 0), "'traceback'")) 392 assert(string.find(debug.traceback(), "^stack traceback:\n")) 393 394 -- testing debugging of coroutines 395 396 local function checktraceback (co, p) 397 local tb = debug.traceback(co) 398 local i = 0 399 for l in string.gmatch(tb, "[^\n]+\n?") do 400 assert(i == 0 or string.find(l, p[i])) 401 i = i+1 402 end 403 assert(p[i] == nil) 404 end 405 406 407 local function f (n) 408 if n > 0 then return f(n-1) 409 else coroutine.yield() end 410 end 411 412 local co = coroutine.create(f) 413 coroutine.resume(co, 3) 414 checktraceback(co, {"yield", "db.lua", "tail", "tail", "tail"}) 415 416 417 co = coroutine.create(function (x) 418 local a = 1 419 coroutine.yield(debug.getinfo(1, "l")) 420 coroutine.yield(debug.getinfo(1, "l").currentline) 421 return a 422 end) 423 424 local tr = {} 425 local foo = function (e, l) table.insert(tr, l) end 426 debug.sethook(co, foo, "l") 427 428 local _, l = coroutine.resume(co, 10) 429 local x = debug.getinfo(co, 1, "lfLS") 430 assert(x.currentline == l.currentline and x.activelines[x.currentline]) 431 assert(type(x.func) == "function") 432 for i=x.linedefined + 1, x.lastlinedefined do 433 assert(x.activelines[i]) 434 x.activelines[i] = nil 435 end 436 assert(next(x.activelines) == nil) -- no 'extra' elements 437 assert(debug.getinfo(co, 2) == nil) 438 local a,b = debug.getlocal(co, 1, 1) 439 assert(a == "x" and b == 10) 440 a,b = debug.getlocal(co, 1, 2) 441 assert(a == "a" and b == 1) 442 debug.setlocal(co, 1, 2, "hi") 443 assert(debug.gethook(co) == foo) 444 assert(table.getn(tr) == 2 and 445 tr[1] == l.currentline-1 and tr[2] == l.currentline) 446 447 a,b,c = pcall(coroutine.resume, co) 448 assert(a and b and c == l.currentline+1) 449 checktraceback(co, {"yield", "in function <"}) 450 451 a,b = coroutine.resume(co) 452 assert(a and b == "hi") 453 assert(table.getn(tr) == 4 and tr[4] == l.currentline+2) 454 assert(debug.gethook(co) == foo) 455 assert(debug.gethook() == nil) 456 checktraceback(co, {}) 457 458 459 -- check traceback of suspended (or dead with error) coroutines 460 461 function f(i) if i==0 then error(i) else coroutine.yield(); f(i-1) end end 462 463 co = coroutine.create(function (x) f(x) end) 464 a, b = coroutine.resume(co, 3) 465 t = {"'yield'", "'f'", "in function <"} 466 while coroutine.status(co) == "suspended" do 467 checktraceback(co, t) 468 a, b = coroutine.resume(co) 469 table.insert(t, 2, "'f'") -- one more recursive call to 'f' 470 end 471 t[1] = "'error'" 472 checktraceback(co, t) 473 474 475 -- test acessing line numbers of a coroutine from a resume inside 476 -- a C function (this is a known bug in Lua 5.0) 477 478 local function g(x) 479 coroutine.yield(x) 480 end 481 482 local function f (i) 483 debug.sethook(function () end, "l") 484 for j=1,1000 do 485 g(i+j) 486 end 487 end 488 489 local co = coroutine.wrap(f) 490 co(10) 491 pcall(co) 492 pcall(co) 493 494 495 assert(type(debug.getregistry()) == "table") 496 497 498 print"OK" 499