github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/testdata/lua-5.3.3-tests/errors.lua (about) 1 -- $Id: errors.lua,v 1.92 2016/03/07 19:27:08 roberto Exp $ 2 3 print("testing errors") 4 5 local debug = require"debug" 6 7 -- avoid problems with 'strict' module (which may generate other error messages) 8 local mt = getmetatable(_G) or {} 9 local oldmm = mt.__index 10 mt.__index = nil 11 12 local function checkerr (msg, f, ...) 13 local st, err = pcall(f, ...) 14 assert(not st and string.find(err, msg)) 15 end 16 17 18 local function doit (s) 19 local f, msg = load(s) 20 if f == nil then return msg end 21 local cond, msg = pcall(f) 22 return (not cond) and msg 23 end 24 25 26 local function checkmessage (prog, msg) 27 local m = doit(prog) 28 assert(string.find(m, msg, 1, true)) 29 end 30 31 local function checksyntax (prog, extra, token, line) 32 local msg = doit(prog) 33 if not string.find(token, "^<%a") and not string.find(token, "^char%(") 34 then token = "'"..token.."'" end 35 token = string.gsub(token, "(%p)", "%%%1") 36 -- local pt = string.format([[^%%[string ".*"%%]:%d: .- near %s$]], 37 -- line, token) 38 local pt = string.format([[%%[string ".*"%%]:%d]], line) 39 assert(string.find(msg, pt)) 40 assert(string.find(msg, msg, 1, true)) 41 end 42 43 44 -- test error message with no extra info 45 assert(doit("error('hi', 0)") == 'hi') 46 47 -- test error message with no info 48 assert(doit("error()") == nil) 49 50 51 -- test common errors/errors that crashed in the past 52 assert(doit("table.unpack({}, 1, n=2^30)")) 53 assert(doit("a=math.sin()")) 54 assert(not doit("tostring(1)") and doit("tostring()")) 55 assert(doit"tonumber()") 56 assert(doit"repeat until 1; a") 57 assert(doit"return;;") 58 assert(doit"assert(false)") 59 assert(doit"assert(nil)") 60 assert(doit("function a (... , ...) end")) 61 assert(doit("function a (, ...) end")) 62 assert(doit("local t={}; t = t[#t] + 1")) 63 64 -- checksyntax([[ 65 -- local a = {4 66 67 -- ]], "'}' expected (to close '{' at line 1)", "<eof>", 3) 68 69 70 -- tests for better error messages 71 72 checkmessage("a = {} + 1", "arithmetic") 73 checkmessage("a = {} | 1", "bitwise operation") 74 checkmessage("a = {} < 1", "attempt to compare") 75 checkmessage("a = {} <= 1", "attempt to compare") 76 77 -- TODO or spec: no way to support 78 -- checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'") 79 -- checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'") 80 -- checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'") 81 assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'")) 82 checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number") 83 checkmessage("a=(1)..{}", "a table value") 84 85 checkmessage("a = #print", "length of a function value") 86 checkmessage("a = #3", "length of a number value") 87 88 aaa = nil 89 -- checkmessage("aaa.bbb:ddd(9)", "global 'aaa'") 90 -- checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'") 91 -- checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'") 92 -- checkmessage("local a,b,c; (function () a = b+1 end)()", "upvalue 'b'") 93 assert(not doit"local aaa={bbb={ddd=next}}; aaa.bbb:ddd(nil)") 94 95 -- upvalues being indexed do not go to the stack 96 -- checkmessage("local a,b,cc; (function () a = cc[1] end)()", "upvalue 'cc'") 97 -- checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'") 98 99 -- checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'") 100 101 -- checkmessage("b=1; local aaa='a'; x=aaa+b", "local 'aaa'") 102 -- checkmessage("aaa={}; x=3/aaa", "global 'aaa'") 103 -- checkmessage("aaa='2'; b=nil;x=aaa*b", "global 'b'") 104 -- checkmessage("aaa={}; x=-aaa", "global 'aaa'") 105 106 -- short circuit 107 -- checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)", 108 -- "local 'bbbb'") 109 -- checkmessage("a=1; local a,bbbb=2,3; a = bbbb(1) or a(3)", "local 'bbbb'") 110 -- checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'") 111 checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value") 112 assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'")) 113 assert(not string.find(doit"aaa={}; (aaa or aaa)()", "'aaa'")) 114 115 checkmessage("print(print < 10)", "function with number") 116 checkmessage("print(print < print)", "two function values") 117 checkmessage("print('10' < 10)", "string with number") 118 checkmessage("print(10 < '23')", "number with string") 119 120 -- float->integer conversions 121 -- checkmessage("local a = 2.0^100; x = a << 2", "local a") 122 checkmessage("local a = 1 >> 2.0^100", "has no integer representation") 123 checkmessage("local a = '10' << 2.0^100", "has no integer representation") 124 checkmessage("local a = 2.0^100 & 1", "has no integer representation") 125 checkmessage("local a = 2.0^100 & '1'", "has no integer representation") 126 checkmessage("local a = 2.0 | 1e40", "has no integer representation") 127 checkmessage("local a = 2e100 ~ 1", "has no integer representation") 128 checkmessage("string.sub('a', 2.0^100)", "has no integer representation") 129 checkmessage("string.rep('a', 3.3)", "has no integer representation") 130 checkmessage("return 6e40 & 7", "has no integer representation") 131 checkmessage("return 34 << 7e30", "has no integer representation") 132 checkmessage("return ~-3e40", "has no integer representation") 133 checkmessage("return ~-3.009", "has no integer representation") 134 checkmessage("return 3.009 & 1", "has no integer representation") 135 checkmessage("return 34 >> {}", "table value") 136 checkmessage("a = 24 // 0", "divide by zero") 137 checkmessage("a = 1 % 0", "'n%0'") 138 139 140 -- passing light userdata instead of full userdata 141 _G.D = debug 142 checkmessage([[ 143 -- create light udata 144 local x = D.upvalueid(function () return debug end, 1) 145 D.setuservalue(x, {}) 146 ]], "light userdata") 147 _G.D = nil 148 149 do -- named objects (field '__name') 150 checkmessage("math.sin(io.input())", "(number expected, got FILE*)") 151 _G.XX = setmetatable({}, {__name = "My Type"}) 152 checkmessage("io.input(XX)", "(FILE* expected, got My Type)") 153 checkmessage("return XX + 1", "on a My Type value") 154 checkmessage("return ~io.stdin", "on a FILE* value") 155 checkmessage("return XX < XX", "two My Type values") 156 checkmessage("return {} < XX", "table with My Type") 157 checkmessage("return XX < io.stdin", "My Type with FILE*") 158 _G.XX = nil 159 end 160 161 -- global functions 162 checkmessage("(io.write or print){}", "io.write") 163 checkmessage("(collectgarbage or print){}", "collectgarbage") 164 165 -- errors in functions without debug info 166 do 167 local f = function (a) return a + 1 end 168 f = assert(load(string.dump(f, true))) 169 assert(f(3) == 4) 170 -- checkerr("^%?:%-1:", f, {}) 171 172 -- code with a move to a local var ('OP_MOV A B' with A<B) 173 f = function () local a; a = {}; return a + 2 end 174 -- no debug info (so that 'a' is unknown) 175 f = assert(load(string.dump(f, true))) 176 -- symbolic execution should not get lost 177 -- checkerr("^%?:%-1:.*table value", f) 178 checkerr(".*table value", f) 179 end 180 181 182 -- tests for field accesses after RK limit 183 local t = {} 184 for i = 1, 1000 do 185 t[i] = "a = x" .. i 186 end 187 local s = table.concat(t, "; ") 188 t = nil 189 -- checkmessage(s.."; a = bbb + 1", "global 'bbb'") 190 -- checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'") 191 -- checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") 192 -- checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") 193 194 -- checkmessage([[aaa=9 195 -- repeat until 3==3 196 -- local x=math.sin(math.cos(3)) 197 -- if math.sin(1) == x then return math.sin(1) end -- tail call 198 -- local a,b = 1, { 199 -- {x='a'..'b'..'c', y='b', z=x}, 200 -- {1,2,3,4,5} or 3+3<=3+3, 201 -- 3+1>3+1, 202 -- {d = x and aaa[x or y]}} 203 -- ]], "global 'aaa'") 204 205 -- checkmessage([[ 206 -- local x,y = {},1 207 -- if math.sin(1) == 0 then return 3 end -- return 208 -- x.a()]], "field 'a'") 209 210 -- checkmessage([[ 211 -- prefix = nil 212 -- insert = nil 213 -- while 1 do 214 -- local a 215 -- if nil then break end 216 -- insert(prefix, a) 217 -- end]], "global 'insert'") 218 219 -- TODO or spec 220 -- checkmessage([[ -- tail call 221 -- return math.sin("a") 222 -- ]], "'sin'") 223 checkmessage([[ -- tail call 224 return math.sin("a") 225 ]], "'math.sin'") 226 227 checkmessage([[collectgarbage("nooption")]], "invalid option") 228 229 checkmessage([[x = print .. "a"]], "concatenate") 230 checkmessage([[x = "a" .. false]], "concatenate") 231 checkmessage([[x = {} .. 2]], "concatenate") 232 233 -- checkmessage("getmetatable(io.stdin).__gc()", "no value") 234 235 -- checkmessage([[ 236 -- local Var 237 -- local function main() 238 -- NoSuchName (function() Var=0 end) 239 -- end 240 -- main() 241 -- ]], "global 'NoSuchName'") 242 print'+' 243 244 a = {}; setmetatable(a, {__index = string}) 245 checkmessage("a:sub()", "bad self") 246 checkmessage("string.sub('a', {})", "#2") 247 checkmessage("('a'):sub{}", "#1") 248 249 checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") 250 checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'") 251 252 -- tests for errors in coroutines 253 254 -- local function f (n) 255 -- local c = coroutine.create(f) 256 -- local a,b = coroutine.resume(c) 257 -- return b 258 -- end 259 -- assert(string.find(f(), "C stack overflow")) 260 261 -- checkmessage("coroutine.yield()", "outside a coroutine") 262 263 -- f = coroutine.wrap(function () table.sort({1,2,3}, coroutine.yield) end) 264 -- checkerr("yield across", f) 265 266 267 -- testing size of 'source' info; size of buffer for that info is 268 -- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'. 269 idsize = 60 - 1 270 local function checksize (source) 271 -- syntax error 272 local _, msg = load("x", source) 273 msg = string.match(msg, "^([^:]*):") -- get source (1st part before ':') 274 assert(msg:len() <= idsize) 275 end 276 277 for i = 60 - 10, 60 + 10 do -- check border cases around 60 278 checksize("@" .. string.rep("x", i)) -- file names 279 checksize(string.rep("x", i - 10)) -- string sources 280 checksize("=" .. string.rep("x", i)) -- exact sources 281 end 282 283 284 -- testing line error 285 286 local function lineerror (s, l) 287 local err,msg = pcall(load(s)) 288 local line = string.match(msg, ":(%d+):") 289 assert((line and line+0) == l) 290 end 291 292 -- lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2) 293 -- lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3) 294 -- lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4) 295 -- lineerror("function a.x.y ()\na=a+1\nend", 1) 296 297 -- lineerror("a = \na\n+\n{}", 3) 298 -- lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6) 299 -- lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3) 300 301 -- lineerror("a\n=\n-\n\nprint\n;", 3) 302 303 -- lineerror([[ 304 -- a 305 -- ( 306 -- 23) 307 -- ]], 1) 308 309 -- lineerror([[ 310 -- local a = {x = 13} 311 -- a 312 -- . 313 -- x 314 -- ( 315 -- 23 316 -- ) 317 -- ]], 2) 318 319 -- lineerror([[ 320 -- local a = {x = 13} 321 -- a 322 -- . 323 -- x 324 -- ( 325 -- 23 + a 326 -- ) 327 -- ]], 6) 328 329 -- local p = [[ 330 -- function g() f() end 331 -- function f(x) error('a', X) end 332 -- g() 333 -- ]] 334 -- X=3;lineerror((p), 3) 335 -- X=0;lineerror((p), nil) 336 -- X=1;lineerror((p), 2) 337 -- X=2;lineerror((p), 1) 338 339 340 -- if not _soft then 341 -- -- several tests that exaust the Lua stack 342 -- collectgarbage() 343 -- print"testing stack overflow" 344 -- C = 0 345 -- local l = debug.getinfo(1, "l").currentline; function y () C=C+1; y() end 346 347 -- local function checkstackmessage (m) 348 -- return (string.find(m, "^.-:%d+: stack overflow")) 349 -- end 350 -- -- repeated stack overflows (to check stack recovery) 351 -- assert(checkstackmessage(doit('y()'))) 352 -- print('+') 353 -- assert(checkstackmessage(doit('y()'))) 354 -- print('+') 355 -- assert(checkstackmessage(doit('y()'))) 356 -- print('+') 357 358 359 -- -- error lines in stack overflow 360 -- C = 0 361 -- local l1 362 -- local function g(x) 363 -- l1 = debug.getinfo(x, "l").currentline; y() 364 -- end 365 -- local _, stackmsg = xpcall(g, debug.traceback, 1) 366 -- print('+') 367 -- local stack = {} 368 -- for line in string.gmatch(stackmsg, "[^\n]*") do 369 -- local curr = string.match(line, ":(%d+):") 370 -- if curr then table.insert(stack, tonumber(curr)) end 371 -- end 372 -- local i=1 373 -- while stack[i] ~= l1 do 374 -- assert(stack[i] == l) 375 -- i = i+1 376 -- end 377 -- assert(i > 15) 378 379 380 -- -- error in error handling 381 -- local res, msg = xpcall(error, error) 382 -- assert(not res and type(msg) == 'string') 383 -- print('+') 384 385 -- local function f (x) 386 -- if x==0 then error('a\n') 387 -- else 388 -- local aux = function () return f(x-1) end 389 -- local a,b = xpcall(aux, aux) 390 -- return a,b 391 -- end 392 -- end 393 -- f(3) 394 395 -- local function loop (x,y,z) return 1 + loop(x, y, z) end 396 397 -- local res, msg = xpcall(loop, function (m) 398 -- assert(string.find(m, "stack overflow")) 399 -- checkerr("error handling", loop) 400 -- assert(math.sin(0) == 0) 401 -- return 15 402 -- end) 403 -- assert(msg == 15) 404 405 -- local f = function () 406 -- for i = 999900, 1000000, 1 do table.unpack({}, 1, i) end 407 -- end 408 -- checkerr("too many results", f) 409 410 -- end 411 412 413 do 414 -- non string messages 415 local t = {} 416 local res, msg = pcall(function () error(t) end) 417 assert(not res and msg == t) 418 419 res, msg = pcall(function () error(nil) end) 420 assert(not res and msg == nil) 421 422 local function f() error{msg='x'} end 423 res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end) 424 assert(msg.msg == 'xy') 425 426 -- 'assert' with extra arguments 427 res, msg = pcall(assert, false, "X", t) 428 assert(not res and msg == "X") 429 430 -- 'assert' with no message 431 res, msg = pcall(function () assert(false) end) 432 local line = string.match(msg, "%w+%.lua:(%d+): assertion failed!$") 433 assert(tonumber(line) == debug.getinfo(1, "l").currentline - 2) 434 435 -- 'assert' with non-string messages 436 res, msg = pcall(assert, false, t) 437 assert(not res and msg == t) 438 439 res, msg = pcall(assert, nil, nil) 440 assert(not res and msg == nil) 441 442 -- 'assert' without arguments 443 res, msg = pcall(assert) 444 -- TODO or spec 445 assert(not res and string.find(msg, "boolean expected")) 446 -- assert(not res and string.find(msg, "value expected")) 447 end 448 449 -- xpcall with arguments 450 a, b, c = xpcall(string.find, error, "alo", "al") 451 assert(a and b == 1 and c == 2) 452 a, b, c = xpcall(string.find, function (x) return {} end, true, "al") 453 assert(not a and type(b) == "table" and c == nil) 454 455 456 print("testing tokens in error messages") 457 checksyntax("syntax error", "", "error", 1) 458 checksyntax("1.000", "", "1.000", 1) 459 checksyntax("[[a]]", "", "[[a]]", 1) 460 checksyntax("'aa'", "", "'aa'", 1) 461 checksyntax("while << do end", "", "<<", 1) 462 checksyntax("for >> do end", "", ">>", 1) 463 464 -- test invalid non-printable char in a chunk 465 checksyntax("a\1a = 1", "", "<\\1>", 1) 466 467 -- test 255 as first char in a chunk 468 checksyntax("\255a = 1", "", "<\\255>", 1) 469 470 doit('I = load("a=9+"); a=3') 471 assert(a==3 and I == nil) 472 print('+') 473 474 lim = 1000 475 if _soft then lim = 100 end 476 for i=1,lim do 477 doit('a = ') 478 doit('a = 4+nil') 479 end 480 481 482 -- testing syntax limits 483 484 -- local maxClevel = 200 -- LUAI_MAXCCALLS (in llimits.h) 485 486 -- local function testrep (init, rep, close, repc) 487 -- local s = init .. string.rep(rep, maxClevel - 10) .. close .. 488 -- string.rep(repc, maxClevel - 10) 489 -- assert(load(s)) -- 190 levels is OK 490 -- s = init .. string.rep(rep, maxClevel + 1) 491 -- checkmessage(s, "too many C levels") 492 -- end 493 494 -- testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment 495 -- testrep("local a; a=", "{", "0", "}") 496 -- testrep("local a; a=", "(", "2", ")") 497 -- testrep("local a; ", "a(", "2", ")") 498 -- testrep("", "do ", "", " end") 499 -- testrep("", "while a do ", "", " end") 500 -- testrep("local a; ", "if a then else ", "", " end") 501 -- testrep("", "function foo () ", "", " end") 502 -- testrep("local a; a=", "a..", "a", "") 503 -- testrep("local a; a=", "a^", "a", "") 504 505 -- checkmessage("a = f(x" .. string.rep(",x", 260) .. ")", "too many registers") 506 507 508 -- testing other limits 509 510 -- upvalues 511 local lim = 127 512 local s = "local function fooA ()\n local " 513 for j = 1,lim do 514 s = s.."a"..j..", " 515 end 516 s = s.."b,c\n" 517 s = s.."local function fooB ()\n local " 518 for j = 1,lim do 519 s = s.."b"..j..", " 520 end 521 s = s.."b\n" 522 s = s.."function fooC () return b+c" 523 local c = 1+2 524 for j = 1,lim do 525 s = s.."+a"..j.."+b"..j 526 c = c + 2 527 end 528 s = s.."\nend end end" 529 local a,b = load(s) 530 -- assert(c > 255 and string.find(b, "too many upvalues") and 531 -- string.find(b, "line 5")) 532 assert(c > 255 and string.find(b, "too many upvalues")) 533 534 -- local variables 535 s = "\nfunction foo ()\n local " 536 for j = 1,300 do 537 s = s.."a"..j..", " 538 end 539 -- s = s.."b\n" 540 s = s.."b\nend" 541 local a,b = load(s) 542 -- assert(string.find(b, "line 2") and string.find(b, "too many local variables")) 543 assert(string.find(b, "too many local variables")) 544 545 mt.__index = oldmm 546 547 print('OK')