main.lua (15336B)
1 # testing special comment on first line 2 -- $Id: testes/main.lua $ 3 -- See Copyright Notice in file all.lua 4 5 -- most (all?) tests here assume a reasonable "Unix-like" shell 6 if _port then return end 7 8 -- use only "double quotes" inside shell scripts (better change to 9 -- run on Windows) 10 11 12 print ("testing stand-alone interpreter") 13 14 assert(os.execute()) -- machine has a system command 15 16 local arg = arg or ARG 17 18 local prog = os.tmpname() 19 local otherprog = os.tmpname() 20 local out = os.tmpname() 21 22 local progname 23 do 24 local i = 0 25 while arg[i] do i=i-1 end 26 progname = arg[i+1] 27 end 28 print("progname: "..progname) 29 30 31 local prepfile = function (s, mod, p) 32 mod = mod and "wb" or "w" -- mod true means binary files 33 p = p or prog -- file to write the program 34 local f = io.open(p, mod) 35 f:write(s) 36 assert(f:close()) 37 end 38 39 local function getoutput () 40 local f = io.open(out) 41 local t = f:read("a") 42 f:close() 43 assert(os.remove(out)) 44 return t 45 end 46 47 local function checkprogout (s) 48 -- expected result must end with new line 49 assert(string.sub(s, -1) == "\n") 50 local t = getoutput() 51 for line in string.gmatch(s, ".-\n") do 52 assert(string.find(t, line, 1, true)) 53 end 54 end 55 56 local function checkout (s) 57 local t = getoutput() 58 if s ~= t then print(string.format("'%s' - '%s'\n", s, t)) end 59 assert(s == t) 60 return t 61 end 62 63 64 local function RUN (p, ...) 65 p = string.gsub(p, "lua", '"'..progname..'"', 1) 66 local s = string.format(p, ...) 67 assert(os.execute(s)) 68 end 69 70 71 local function NoRun (msg, p, ...) 72 p = string.gsub(p, "lua", '"'..progname..'"', 1) 73 local s = string.format(p, ...) 74 s = string.format("%s >%s 2>&1", s, out) -- send output and error to 'out' 75 assert(not os.execute(s)) 76 assert(string.find(getoutput(), msg, 1, true)) -- check error message 77 end 78 79 RUN('lua -v') 80 81 print(string.format("(temporary program file used in these tests: %s)", prog)) 82 83 -- running stdin as a file 84 prepfile"" 85 RUN('lua - < %s > %s', prog, out) 86 checkout("") 87 88 prepfile[[ 89 print( 90 1, a 91 ) 92 ]] 93 RUN('lua - < %s > %s', prog, out) 94 checkout("1\tnil\n") 95 96 RUN('echo "print(10)\nprint(2)\n" | lua > %s', out) 97 checkout("10\n2\n") 98 99 100 -- testing BOM 101 prepfile("\xEF\xBB\xBF") 102 RUN('lua %s > %s', prog, out) 103 checkout("") 104 105 prepfile("\xEF\xBB\xBFprint(3)") 106 RUN('lua %s > %s', prog, out) 107 checkout("3\n") 108 109 prepfile("\xEF\xBB\xBF# comment!!\nprint(3)") 110 RUN('lua %s > %s', prog, out) 111 checkout("3\n") 112 113 -- bad BOMs 114 prepfile("\xEF", true) 115 NoRun("unexpected symbol", 'lua %s', prog) 116 117 prepfile("\xEF\xBB", true) 118 NoRun("unexpected symbol", 'lua %s', prog) 119 120 prepfile("\xEFprint(3)", true) 121 NoRun("unexpected symbol", 'lua %s', prog) 122 123 prepfile("\xEF\xBBprint(3)", true) 124 NoRun("unexpected symbol", 'lua %s', prog) 125 126 127 -- test option '-' 128 RUN('echo "print(arg[1])" | lua - -h > %s', out) 129 checkout("-h\n") 130 131 -- test environment variables used by Lua 132 133 prepfile("print(package.path)") 134 135 -- test LUA_PATH 136 RUN('env LUA_INIT= LUA_PATH=x lua %s > %s', prog, out) 137 checkout("x\n") 138 139 -- test LUA_PATH_version 140 RUN('env LUA_INIT= LUA_PATH_5_5=y LUA_PATH=x lua %s > %s', prog, out) 141 checkout("y\n") 142 143 -- test LUA_CPATH 144 prepfile("print(package.cpath)") 145 RUN('env LUA_INIT= LUA_CPATH=xuxu lua %s > %s', prog, out) 146 checkout("xuxu\n") 147 148 -- test LUA_CPATH_version 149 RUN('env LUA_INIT= LUA_CPATH_5_5=yacc LUA_CPATH=x lua %s > %s', prog, out) 150 checkout("yacc\n") 151 152 -- test LUA_INIT (and its access to 'arg' table) 153 prepfile("print(X)") 154 RUN('env LUA_INIT="X=tonumber(arg[1])" lua %s 3.2 > %s', prog, out) 155 checkout("3.2\n") 156 157 -- test LUA_INIT_version 158 prepfile("print(X)") 159 RUN('env LUA_INIT_5_5="X=10" LUA_INIT="X=3" lua %s > %s', prog, out) 160 checkout("10\n") 161 162 -- test LUA_INIT for files 163 prepfile("x = x or 10; print(x); x = x + 1") 164 RUN('env LUA_INIT="@%s" lua %s > %s', prog, prog, out) 165 checkout("10\n11\n") 166 167 -- test errors in LUA_INIT 168 NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua') 169 170 -- test option '-E' 171 local defaultpath, defaultCpath 172 173 do 174 prepfile("print(package.path, package.cpath)") 175 RUN('env LUA_INIT="error(10)" LUA_PATH=xxx LUA_CPATH=xxx lua -E %s > %s', 176 prog, out) 177 local output = getoutput() 178 defaultpath = string.match(output, "^(.-)\t") 179 defaultCpath = string.match(output, "\t(.-)$") 180 181 -- running with an empty environment 182 RUN('env -i lua %s > %s', prog, out) 183 local out = getoutput() 184 assert(defaultpath == string.match(output, "^(.-)\t")) 185 assert(defaultCpath == string.match(output, "\t(.-)$")) 186 end 187 188 -- paths did not change 189 assert(not string.find(defaultpath, "xxx") and 190 string.find(defaultpath, "lua") and 191 not string.find(defaultCpath, "xxx") and 192 string.find(defaultCpath, "lua")) 193 194 195 -- test replacement of ';;' to default path 196 local function convert (p) 197 prepfile("print(package.path)") 198 RUN('env LUA_PATH="%s" lua %s > %s', p, prog, out) 199 local expected = getoutput() 200 expected = string.sub(expected, 1, -2) -- cut final end of line 201 if string.find(p, ";;") then 202 p = string.gsub(p, ";;", ";"..defaultpath..";") 203 p = string.gsub(p, "^;", "") -- remove ';' at the beginning 204 p = string.gsub(p, ";$", "") -- remove ';' at the end 205 end 206 assert(p == expected) 207 end 208 209 convert(";") 210 convert(";;") 211 convert("a;;b") 212 convert(";;b") 213 convert("a;;") 214 convert("a;b;;c") 215 216 217 -- test -l over multiple libraries 218 prepfile("print(1); a=2; return {x=15}") 219 prepfile(("print(a); print(_G['%s'].x)"):format(prog), false, otherprog) 220 RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out) 221 checkout("1\n2\n15\n2\n15\n") 222 223 -- test explicit global names in -l 224 prepfile("print(str.upper'alo alo', m.max(10, 20))") 225 RUN("lua -l 'str=string' '-lm=math' -e 'print(m.sin(0))' %s > %s", prog, out) 226 checkout("0.0\nALO ALO\t20\n") 227 228 229 -- test module names with version sufix ("libs/lib2-v2") 230 RUN("env LUA_CPATH='./libs/?.so' lua -l lib2-v2 -e 'print(lib2.id())' > %s", 231 out) 232 checkout("true\n") 233 234 235 -- test 'arg' table 236 local a = [[ 237 assert(#arg == 3 and arg[1] == 'a' and 238 arg[2] == 'b' and arg[3] == 'c') 239 assert(arg[-1] == '--' and arg[-2] == "-e " and arg[-3] == '%s') 240 assert(arg[4] == undef and arg[-4] == undef) 241 local a, b, c = ... 242 assert(... == 'a' and a == 'a' and b == 'b' and c == 'c') 243 ]] 244 a = string.format(a, progname) 245 prepfile(a) 246 RUN('lua "-e " -- %s a b c', prog) -- "-e " runs an empty command 247 248 -- test 'arg' availability in libraries 249 prepfile"assert(arg)" 250 prepfile("assert(arg)", false, otherprog) 251 RUN('env LUA_PATH="?;;" lua -l%s - < %s', prog, otherprog) 252 253 -- test messing up the 'arg' table 254 RUN('echo "print(...)" | lua -e "arg[1] = 100" - > %s', out) 255 checkout("100\n") 256 NoRun("'arg' is not a table", 'echo "" | lua -e "arg = 1" -') 257 258 -- test error in 'print' 259 RUN('echo 10 | lua -e "print=nil" -i > /dev/null 2> %s', out) 260 assert(string.find(getoutput(), "error calling 'print'")) 261 262 -- test 'debug.debug' 263 RUN('echo "io.stderr:write(1000)\ncont" | lua -e "require\'debug\'.debug()" 2> %s', out) 264 checkout("lua_debug> 1000lua_debug> ") 265 266 do -- test warning for locals 267 RUN('echo " local x" | lua -i > %s 2>&1', out) 268 assert(string.find(getoutput(), "warning: ")) 269 270 RUN('echo "local1 = 10\nlocal1 + 3" | lua -i > %s 2>&1', out) 271 local t = getoutput() 272 assert(not string.find(t, "warning")) 273 assert(string.find(t, "13")) 274 end 275 276 print("testing warnings") 277 278 -- no warnings by default 279 RUN('echo "io.stderr:write(1); warn[[XXX]]" | lua 2> %s', out) 280 checkout("1") 281 282 prepfile[[ 283 warn("@allow") -- unknown control, ignored 284 warn("@off", "XXX", "@off") -- these are not control messages 285 warn("@off") -- this one is 286 warn("@on", "YYY", "@on") -- not control, but warn is off 287 warn("@off") -- keep it off 288 warn("@on") -- restart warnings 289 warn("", "@on") -- again, no control, real warning 290 warn("@on") -- keep it "started" 291 warn("Z", "Z", "Z") -- common warning 292 ]] 293 RUN('lua -W %s 2> %s', prog, out) 294 checkout[[ 295 Lua warning: @offXXX@off 296 Lua warning: @on 297 Lua warning: ZZZ 298 ]] 299 300 prepfile[[ 301 warn("@allow") 302 -- create two objects to be finalized when closing state 303 -- the errors in the finalizers must generate warnings 304 u1 = setmetatable({}, {__gc = function () error("XYZ") end}) 305 u2 = setmetatable({}, {__gc = function () error("ZYX") end}) 306 ]] 307 RUN('lua -W %s 2> %s', prog, out) 308 checkprogout("ZYX)\nXYZ)\n") 309 310 -- bug since 5.2: finalizer called when closing a state could 311 -- subvert finalization order 312 prepfile[[ 313 -- ensure tables will be collected only at the end of the program 314 collectgarbage"stop" 315 316 print("creating 1") 317 -- this finalizer should be called last 318 setmetatable({}, {__gc = function () print(1) end}) 319 320 print("creating 2") 321 setmetatable({}, {__gc = function () 322 print("2") 323 print("creating 3") 324 -- this finalizer should not be called, as object will be 325 -- created after 'lua_close' has been called 326 setmetatable({}, {__gc = function () print(3) end}) 327 print(collectgarbage() or false) -- cannot call collector here 328 os.exit(0, true) 329 end}) 330 ]] 331 RUN('lua -W %s > %s', prog, out) 332 checkout[[ 333 creating 1 334 creating 2 335 2 336 creating 3 337 false 338 1 339 ]] 340 341 342 -- test many arguments 343 prepfile[[print(({...})[30])]] 344 RUN('lua %s %s > %s', prog, string.rep(" a", 30), out) 345 checkout("a\n") 346 347 RUN([[lua "-eprint(1)" -ea=3 -e "print(a)" > %s]], out) 348 checkout("1\n3\n") 349 350 -- test iteractive mode 351 prepfile[[ 352 (6*2-6) -- === 353 a = 354 10 355 print(a) 356 a]] 357 RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) 358 checkprogout("6\n10\n10\n\n") 359 360 prepfile("a = [[b\nc\nd\ne]]\na") 361 RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) 362 checkprogout("b\nc\nd\ne\n\n") 363 364 -- input interrupted in continuation line 365 prepfile("a.\n") 366 RUN([[lua -i < %s > /dev/null 2> %s]], prog, out) 367 checkprogout("near <eof>\n") 368 369 local prompt = "alo" 370 prepfile[[ -- 371 a = 2 372 ]] 373 RUN([[lua "-e_PROMPT='%s'" -i < %s > %s]], prompt, prog, out) 374 local t = getoutput() 375 assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt)) 376 377 -- using the prompt default 378 prepfile[[ -- 379 a = 2 380 ]] 381 RUN([[lua -i < %s > %s]], prog, out) 382 local t = getoutput() 383 prompt = "> " -- the default 384 assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt)) 385 386 387 -- non-string prompt 388 prompt = [[ 389 local C = 'X'; 390 _PROMPT=setmetatable({},{__tostring = function () 391 C = C .. 'X'; return C end}) 392 ]] 393 prepfile[[ -- 394 a = 2 395 ]] 396 RUN([[lua -e "%s" -i < %s > %s]], prompt, prog, out) 397 local t = getoutput() 398 -- skip version line and then check the presence of the three prompts 399 assert(string.find(t, "^.-\nXX[^\nX]*\n?XXX[^\nX]*\n?XXXX\n?$")) 400 401 402 -- test for error objects 403 prepfile[[ 404 debug = require "debug" 405 m = {x=0} 406 setmetatable(m, {__tostring = function(x) 407 return tostring(debug.getinfo(4).currentline + x.x) 408 end}) 409 error(m) 410 ]] 411 NoRun(progname .. ": 6\n", [[lua %s]], prog) 412 413 prepfile("error{}") 414 NoRun("error object is a table value", [[lua %s]], prog) 415 416 417 -- chunk broken in many lines 418 local s = [=[ -- 419 function f ( x ) 420 local a = [[ 421 xuxu 422 ]] 423 local b = "\ 424 xuxu\n" 425 if x == 11 then return 1 + 12 , 2 + 20 end --[[ test multiple returns ]] 426 return x + 1 427 --\\ 428 end 429 return( f( 100 ) ) 430 assert( a == b ) 431 do return f( 11 ) end ]=] 432 s = string.gsub(s, ' ', '\n\n') -- change all spaces for newlines 433 prepfile(s) 434 RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) 435 checkprogout("101\n13\t22\n\n") 436 437 prepfile[[#comment in 1st line without \n at the end]] 438 RUN('lua %s', prog) 439 440 -- first-line comment with binary file 441 prepfile("#comment\n" .. string.dump(load("print(3)")), true) 442 RUN('lua %s > %s', prog, out) 443 checkout('3\n') 444 445 -- close Lua with an open file 446 prepfile(string.format([[io.output(%q); io.write('alo')]], out)) 447 RUN('lua %s', prog) 448 checkout('alo') 449 450 -- bug in 5.2 beta (extra \0 after version line) 451 RUN([[lua -v -e"print'hello'" > %s]], out) 452 t = getoutput() 453 assert(string.find(t, "PUC%-Rio\nhello")) 454 455 456 -- testing os.exit 457 prepfile("os.exit(nil, true)") 458 RUN('lua %s', prog) 459 prepfile("os.exit(0, true)") 460 RUN('lua %s', prog) 461 prepfile("os.exit(true, true)") 462 RUN('lua %s', prog) 463 prepfile("os.exit(1, true)") 464 NoRun("", "lua %s", prog) -- no message 465 prepfile("os.exit(false, true)") 466 NoRun("", "lua %s", prog) -- no message 467 468 469 -- to-be-closed variables in main chunk 470 prepfile[[ 471 local x <close> = setmetatable({}, 472 {__close = function (self, err) 473 assert(err == nil) 474 print("Ok") 475 end}) 476 local e1 <close> = setmetatable({}, {__close = function () print(120) end}) 477 os.exit(true, true) 478 ]] 479 RUN('lua %s > %s', prog, out) 480 checkprogout("120\nOk\n") 481 482 483 -- remove temporary files 484 assert(os.remove(prog)) 485 assert(os.remove(otherprog)) 486 assert(not os.remove(out)) 487 488 -- invalid options 489 NoRun("unrecognized option '-h'", "lua -h") 490 NoRun("unrecognized option '---'", "lua ---") 491 NoRun("unrecognized option '-Ex'", "lua -Ex") 492 NoRun("unrecognized option '-vv'", "lua -vv") 493 NoRun("unrecognized option '-iv'", "lua -iv") 494 NoRun("'-e' needs argument", "lua -e") 495 NoRun("syntax error", "lua -e a") 496 NoRun("'-l' needs argument", "lua -l") 497 498 499 if T then -- test library? 500 print("testing 'not enough memory' to create a state") 501 NoRun("not enough memory", "env MEMLIMIT=100 lua") 502 503 -- testing 'warn' 504 warn("@store") 505 warn("@123", "456", "789") 506 assert(_WARN == "@123456789"); _WARN = false 507 508 warn("zip", "", " ", "zap") 509 assert(_WARN == "zip zap"); _WARN = false 510 warn("ZIP", "", " ", "ZAP") 511 assert(_WARN == "ZIP ZAP"); _WARN = false 512 warn("@normal") 513 end 514 515 do 516 -- 'warn' must get at least one argument 517 local st, msg = pcall(warn) 518 assert(string.find(msg, "string expected")) 519 520 -- 'warn' does not leave unfinished warning in case of errors 521 -- (message would appear in next warning) 522 st, msg = pcall(warn, "SHOULD NOT APPEAR", {}) 523 assert(string.find(msg, "string expected")) 524 end 525 526 print('+') 527 528 print('testing Ctrl C') 529 do 530 -- interrupt a script 531 local function kill (pid) 532 return os.execute(string.format('kill -INT %s 2> /dev/null', pid)) 533 end 534 535 -- function to run a script in background, returning its output file 536 -- descriptor and its pid 537 local function runback (luaprg) 538 -- shell script to run 'luaprg' in background and echo its pid 539 local shellprg = string.format('%s -e "%s" & echo $!', progname, luaprg) 540 local f = io.popen(shellprg, "r") -- run shell script 541 local pid = f:read() -- get pid for Lua script 542 print("(if test fails now, it may leave a Lua script running in \z 543 background, pid " .. pid .. ")") 544 return f, pid 545 end 546 547 -- Lua script that runs protected infinite loop and then prints '42' 548 local f, pid = runback[[ 549 pcall(function () print(12); while true do end end); print(42)]] 550 -- wait until script is inside 'pcall' 551 assert(f:read() == "12") 552 kill(pid) -- send INT signal to Lua script 553 -- check that 'pcall' captured the exception and script continued running 554 assert(f:read() == "42") -- expected output 555 assert(f:close()) 556 print("done") 557 558 -- Lua script in a long unbreakable search 559 local f, pid = runback[[ 560 print(15); string.find(string.rep('a', 100000), '.*b')]] 561 -- wait (so script can reach the loop) 562 assert(f:read() == "15") 563 assert(os.execute("sleep 1")) 564 -- must send at least two INT signals to stop this Lua script 565 local n = 100 566 for i = 0, 100 do -- keep sending signals 567 if not kill(pid) then -- until it fails 568 n = i -- number of non-failed kills 569 break 570 end 571 end 572 assert(f:close()) 573 assert(n >= 2) 574 print(string.format("done (with %d kills)", n)) 575 576 end 577 578 print("OK")