lua

A copy of the Lua development repository
Log | Files | Refs | README

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")