123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- # testing special comment on first line
- -- $Id: testes/main.lua $
- -- See Copyright Notice in file lua.h
- -- most (all?) tests here assume a reasonable "Unix-like" shell
- if _port then return end
- -- use only "double quotes" inside shell scripts (better change to
- -- run on Windows)
- print ("testing stand-alone interpreter")
- assert(os.execute()) -- machine has a system command
- local arg = arg or ARG
- local prog = os.tmpname()
- local otherprog = os.tmpname()
- local out = os.tmpname()
- local progname
- do
- local i = 0
- while arg[i] do i=i-1 end
- progname = arg[i+1]
- end
- print("progname: "..progname)
- local prepfile = function (s, mod, p)
- mod = mod and "wb" or "w" -- mod true means binary files
- p = p or prog -- file to write the program
- local f = io.open(p, mod)
- f:write(s)
- assert(f:close())
- end
- local function getoutput ()
- local f = io.open(out)
- local t = f:read("a")
- f:close()
- assert(os.remove(out))
- return t
- end
- local function checkprogout (s)
- -- expected result must end with new line
- assert(string.sub(s, -1) == "\n")
- local t = getoutput()
- for line in string.gmatch(s, ".-\n") do
- assert(string.find(t, line, 1, true))
- end
- end
- local function checkout (s)
- local t = getoutput()
- if s ~= t then print(string.format("'%s' - '%s'\n", s, t)) end
- assert(s == t)
- return t
- end
- local function RUN (p, ...)
- p = string.gsub(p, "lua", '"'..progname..'"', 1)
- local s = string.format(p, ...)
- assert(os.execute(s))
- end
- local function NoRun (msg, p, ...)
- p = string.gsub(p, "lua", '"'..progname..'"', 1)
- local s = string.format(p, ...)
- s = string.format("%s >%s 2>&1", s, out) -- send output and error to 'out'
- assert(not os.execute(s))
- assert(string.find(getoutput(), msg, 1, true)) -- check error message
- end
- RUN('lua -v')
- print(string.format("(temporary program file used in these tests: %s)", prog))
- -- running stdin as a file
- prepfile""
- RUN('lua - < %s > %s', prog, out)
- checkout("")
- prepfile[[
- print(
- 1, a
- )
- ]]
- RUN('lua - -- < %s > %s', prog, out)
- checkout("1\tnil\n")
- RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
- checkout("10\n2\n")
- -- testing BOM
- prepfile("\xEF\xBB\xBF")
- RUN('lua %s > %s', prog, out)
- checkout("")
- prepfile("\xEF\xBB\xBFprint(3)")
- RUN('lua %s > %s', prog, out)
- checkout("3\n")
- prepfile("\xEF\xBB\xBF# comment!!\nprint(3)")
- RUN('lua %s > %s', prog, out)
- checkout("3\n")
- -- bad BOMs
- prepfile("\xEF", true)
- NoRun("unexpected symbol", 'lua %s', prog)
- prepfile("\xEF\xBB", true)
- NoRun("unexpected symbol", 'lua %s', prog)
- prepfile("\xEFprint(3)", true)
- NoRun("unexpected symbol", 'lua %s', prog)
- prepfile("\xEF\xBBprint(3)", true)
- NoRun("unexpected symbol", 'lua %s', prog)
- -- test option '-'
- RUN('echo "print(arg[1])" | lua - -h > %s', out)
- checkout("-h\n")
- -- test environment variables used by Lua
- prepfile("print(package.path)")
- -- test LUA_PATH
- RUN('env LUA_INIT= LUA_PATH=x lua -- %s > %s', prog, out)
- checkout("x\n")
- -- test LUA_PATH_version
- RUN('env LUA_INIT= LUA_PATH_5_5=y LUA_PATH=x lua %s > %s', prog, out)
- checkout("y\n")
- -- test LUA_CPATH
- prepfile("print(package.cpath)")
- RUN('env LUA_INIT= LUA_CPATH=xuxu lua %s > %s', prog, out)
- checkout("xuxu\n")
- -- test LUA_CPATH_version
- RUN('env LUA_INIT= LUA_CPATH_5_5=yacc LUA_CPATH=x lua %s > %s', prog, out)
- checkout("yacc\n")
- -- test LUA_INIT (and its access to 'arg' table)
- prepfile("print(X)")
- RUN('env LUA_INIT="X=tonumber(arg[1])" lua %s 3.2 > %s', prog, out)
- checkout("3.2\n")
- -- test LUA_INIT_version
- prepfile("print(X)")
- RUN('env LUA_INIT_5_5="X=10" LUA_INIT="X=3" lua %s > %s', prog, out)
- checkout("10\n")
- -- test LUA_INIT for files
- prepfile("x = x or 10; print(x); x = x + 1")
- RUN('env LUA_INIT="@%s" lua %s > %s', prog, prog, out)
- checkout("10\n11\n")
- -- test errors in LUA_INIT
- NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua')
- -- test option '-E'
- local defaultpath, defaultCpath
- do
- prepfile("print(package.path, package.cpath)")
- RUN('env LUA_INIT="error(10)" LUA_PATH=xxx LUA_CPATH=xxx lua -E %s > %s',
- prog, out)
- local output = getoutput()
- defaultpath = string.match(output, "^(.-)\t")
- defaultCpath = string.match(output, "\t(.-)$")
- -- running with an empty environment
- RUN('env -i lua %s > %s', prog, out)
- local out = getoutput()
- assert(defaultpath == string.match(output, "^(.-)\t"))
- assert(defaultCpath == string.match(output, "\t(.-)$"))
- end
- -- paths did not change
- assert(not string.find(defaultpath, "xxx") and
- string.find(defaultpath, "lua") and
- not string.find(defaultCpath, "xxx") and
- string.find(defaultCpath, "lua"))
- -- test replacement of ';;' to default path
- local function convert (p)
- prepfile("print(package.path)")
- RUN('env LUA_PATH="%s" lua %s > %s', p, prog, out)
- local expected = getoutput()
- expected = string.sub(expected, 1, -2) -- cut final end of line
- if string.find(p, ";;") then
- p = string.gsub(p, ";;", ";"..defaultpath..";")
- p = string.gsub(p, "^;", "") -- remove ';' at the beginning
- p = string.gsub(p, ";$", "") -- remove ';' at the end
- end
- assert(p == expected)
- end
- convert(";")
- convert(";;")
- convert("a;;b")
- convert(";;b")
- convert("a;;")
- convert("a;b;;c")
- -- test -l over multiple libraries
- prepfile("print(1); a=2; return {x=15}")
- prepfile(("print(a); print(_G['%s'].x)"):format(prog), false, otherprog)
- RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out)
- checkout("1\n2\n15\n2\n15\n")
- -- test explicit global names in -l
- prepfile("print(str.upper'alo alo', m.max(10, 20))")
- RUN("lua -l 'str=string' '-lm=math' -e 'print(m.sin(0))' %s > %s", prog, out)
- checkout("0.0\nALO ALO\t20\n")
- -- test module names with version suffix ("libs/lib2-v2")
- RUN("env LUA_CPATH='./libs/?.so' lua -l lib2-v2 -e 'print(lib2.id())' > %s",
- out)
- checkout("true\n")
- -- test 'arg' table
- local a = [[
- assert(#arg == 3 and arg[1] == 'a' and
- arg[2] == 'b' and arg[3] == 'c')
- assert(arg[-1] == '--' and arg[-2] == "-e " and arg[-3] == '%s')
- assert(arg[4] == undef and arg[-4] == undef)
- local a, b, c = ...
- assert(... == 'a' and a == 'a' and b == 'b' and c == 'c')
- ]]
- a = string.format(a, progname)
- prepfile(a)
- RUN('lua "-e " -- %s a b c', prog) -- "-e " runs an empty command
- -- test 'arg' availability in libraries
- prepfile"assert(arg)"
- prepfile("assert(arg)", false, otherprog)
- RUN('env LUA_PATH="?;;" lua -l%s - < %s', prog, otherprog)
- -- test messing up the 'arg' table
- RUN('echo "print(...)" | lua -e "arg[1] = 100" - > %s', out)
- checkout("100\n")
- NoRun("'arg' is not a table", 'echo "" | lua -e "arg = 1" -')
- -- test error in 'print'
- RUN('echo 10 | lua -e "print=nil" -i > /dev/null 2> %s', out)
- assert(string.find(getoutput(), "error calling 'print'"))
- -- test 'debug.debug'
- RUN('echo "io.stderr:write(1000)\ncont" | lua -e "require\'debug\'.debug()" 2> %s', out)
- checkout("lua_debug> 1000lua_debug> ")
- do -- test warning for locals
- RUN('echo " local x" | lua -i > %s 2>&1', out)
- assert(string.find(getoutput(), "warning: "))
- RUN('echo "local1 = 10\nlocal1 + 3" | lua -i > %s 2>&1', out)
- local t = getoutput()
- assert(not string.find(t, "warning"))
- assert(string.find(t, "13"))
- end
- print("testing warnings")
- -- no warnings by default
- RUN('echo "io.stderr:write(1); warn[[XXX]]" | lua 2> %s', out)
- checkout("1")
- prepfile[[
- warn("@allow") -- unknown control, ignored
- warn("@off", "XXX", "@off") -- these are not control messages
- warn("@off") -- this one is
- warn("@on", "YYY", "@on") -- not control, but warn is off
- warn("@off") -- keep it off
- warn("@on") -- restart warnings
- warn("", "@on") -- again, no control, real warning
- warn("@on") -- keep it "started"
- warn("Z", "Z", "Z") -- common warning
- ]]
- RUN('lua -W %s 2> %s', prog, out)
- checkout[[
- Lua warning: @offXXX@off
- Lua warning: @on
- Lua warning: ZZZ
- ]]
- prepfile[[
- warn("@allow")
- -- create two objects to be finalized when closing state
- -- the errors in the finalizers must generate warnings
- u1 = setmetatable({}, {__gc = function () error("XYZ") end})
- u2 = setmetatable({}, {__gc = function () error("ZYX") end})
- ]]
- RUN('lua -W %s 2> %s', prog, out)
- checkprogout("ZYX)\nXYZ)\n")
- -- bug since 5.2: finalizer called when closing a state could
- -- subvert finalization order
- prepfile[[
- -- ensure tables will be collected only at the end of the program
- collectgarbage"stop"
- print("creating 1")
- -- this finalizer should be called last
- setmetatable({}, {__gc = function () print(1) end})
- print("creating 2")
- setmetatable({}, {__gc = function ()
- print("2")
- print("creating 3")
- -- this finalizer should not be called, as object will be
- -- created after 'lua_close' has been called
- setmetatable({}, {__gc = function () print(3) end})
- print(collectgarbage() or false) -- cannot call collector here
- os.exit(0, true)
- end})
- ]]
- RUN('lua -W %s > %s', prog, out)
- checkout[[
- creating 1
- creating 2
- 2
- creating 3
- false
- 1
- ]]
- -- test many arguments
- prepfile[[print(({...})[30])]]
- RUN('lua %s %s > %s', prog, string.rep(" a", 30), out)
- checkout("a\n")
- RUN([[lua "-eprint(1)" -ea=3 -e "print(a)" > %s]], out)
- checkout("1\n3\n")
- -- test interactive mode
- prepfile[[
- (6*2-6) -- ===
- a =
- 10
- print(a)
- a]]
- RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
- checkprogout("6\n10\n10\n\n")
- prepfile("a = [[b\nc\nd\ne]]\na")
- RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i -- < %s > %s]], prog, out)
- checkprogout("b\nc\nd\ne\n\n")
- -- input interrupted in continuation line
- prepfile("a.\n")
- RUN([[lua -i < %s > /dev/null 2> %s]], prog, out)
- checkprogout("near <eof>\n")
- local prompt = "alo"
- prepfile[[ --
- a = 2
- ]]
- RUN([[lua "-e_PROMPT='%s'" -i < %s > %s]], prompt, prog, out)
- local t = getoutput()
- assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt))
- -- using the prompt default
- prepfile[[ --
- a = 2
- ]]
- RUN([[lua -i < %s > %s]], prog, out)
- local t = getoutput()
- prompt = "> " -- the default
- assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt))
- -- non-string prompt
- prompt = [[
- local C = 'X';
- _PROMPT=setmetatable({},{__tostring = function ()
- C = C .. 'X'; return C end})
- ]]
- prepfile[[ --
- a = 2
- ]]
- RUN([[lua -e "%s" -i < %s > %s]], prompt, prog, out)
- local t = getoutput()
- -- skip version line and then check the presence of the three prompts
- assert(string.find(t, "^.-\nXX[^\nX]*\n?XXX[^\nX]*\n?XXXX\n?$"))
- -- test for error objects
- prepfile[[
- debug = require "debug"
- m = {x=0}
- setmetatable(m, {__tostring = function(x)
- return tostring(debug.getinfo(4).currentline + x.x)
- end})
- error(m)
- ]]
- NoRun(progname .. ": 6\n", [[lua %s]], prog)
- prepfile("error{}")
- NoRun("error object is a table value", [[lua %s]], prog)
- -- chunk broken in many lines
- local s = [=[ --
- function f ( x )
- local a = [[
- xuxu
- ]]
- local b = "\
- xuxu\n"
- if x == 11 then return 1 + 12 , 2 + 20 end --[[ test multiple returns ]]
- return x + 1
- --\\
- end
- return( f( 100 ) )
- assert( a == b )
- do return f( 11 ) end ]=]
- s = string.gsub(s, ' ', '\n\n') -- change all spaces for newlines
- prepfile(s)
- RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
- checkprogout("101\n13\t22\n\n")
- prepfile[[#comment in 1st line without \n at the end]]
- RUN('lua %s', prog)
- -- first-line comment with binary file
- prepfile("#comment\n" .. string.dump(load("print(3)")), true)
- RUN('lua %s > %s', prog, out)
- checkout('3\n')
- -- close Lua with an open file
- prepfile(string.format([[io.output(%q); io.write('alo')]], out))
- RUN('lua %s', prog)
- checkout('alo')
- -- bug in 5.2 beta (extra \0 after version line)
- RUN([[lua -v -e"print'hello'" > %s]], out)
- t = getoutput()
- assert(string.find(t, "PUC%-Rio\nhello"))
- -- testing os.exit
- prepfile("os.exit(nil, true)")
- RUN('lua %s', prog)
- prepfile("os.exit(0, true)")
- RUN('lua %s', prog)
- prepfile("os.exit(true, true)")
- RUN('lua %s', prog)
- prepfile("os.exit(1, true)")
- NoRun("", "lua %s", prog) -- no message
- prepfile("os.exit(false, true)")
- NoRun("", "lua %s", prog) -- no message
- -- to-be-closed variables in main chunk
- prepfile[[
- local x <close> = setmetatable({},
- {__close = function (self, err)
- assert(err == nil)
- print("Ok")
- end})
- local e1 <close> = setmetatable({}, {__close = function () print(120) end})
- os.exit(true, true)
- ]]
- RUN('lua %s > %s', prog, out)
- checkprogout("120\nOk\n")
- -- remove temporary files
- assert(os.remove(prog))
- assert(os.remove(otherprog))
- assert(not os.remove(out))
- -- invalid options
- NoRun("unrecognized option '-h'", "lua -h")
- NoRun("unrecognized option '---'", "lua ---")
- NoRun("unrecognized option '-Ex'", "lua -Ex --")
- NoRun("unrecognized option '-vv'", "lua -vv")
- NoRun("unrecognized option '-iv'", "lua -iv")
- NoRun("'-e' needs argument", "lua -e")
- NoRun("syntax error", "lua -e a")
- NoRun("'-l' needs argument", "lua -l")
- NoRun("-i", "lua -- -i") -- handles -i as a script name
- if T then -- test library?
- print("testing 'not enough memory' to create a state")
- NoRun("not enough memory", "env MEMLIMIT=100 lua")
- -- testing 'warn'
- warn("@store")
- warn("@123", "456", "789")
- assert(_WARN == "@123456789"); _WARN = false
- warn("zip", "", " ", "zap")
- assert(_WARN == "zip zap"); _WARN = false
- warn("ZIP", "", " ", "ZAP")
- assert(_WARN == "ZIP ZAP"); _WARN = false
- warn("@normal")
- end
- do
- -- 'warn' must get at least one argument
- local st, msg = pcall(warn)
- assert(string.find(msg, "string expected"))
- -- 'warn' does not leave unfinished warning in case of errors
- -- (message would appear in next warning)
- st, msg = pcall(warn, "SHOULD NOT APPEAR", {})
- assert(string.find(msg, "string expected"))
- end
- print('+')
- print('testing Ctrl C')
- do
- -- interrupt a script
- local function kill (pid)
- return os.execute(string.format('kill -INT %s 2> /dev/null', pid))
- end
- -- function to run a script in background, returning its output file
- -- descriptor and its pid
- local function runback (luaprg)
- -- shell script to run 'luaprg' in background and echo its pid
- local shellprg = string.format('%s -e "%s" & echo $!', progname, luaprg)
- local f = io.popen(shellprg, "r") -- run shell script
- local pid = f:read() -- get pid for Lua script
- print("(if test fails now, it may leave a Lua script running in \z
- background, pid " .. pid .. ")")
- return f, pid
- end
- -- Lua script that runs protected infinite loop and then prints '42'
- local f, pid = runback[[
- pcall(function () print(12); while true do end end); print(42)]]
- -- wait until script is inside 'pcall'
- assert(f:read() == "12")
- kill(pid) -- send INT signal to Lua script
- -- check that 'pcall' captured the exception and script continued running
- assert(f:read() == "42") -- expected output
- assert(f:close())
- print("done")
- -- Lua script in a long unbreakable search
- local f, pid = runback[[
- print(15); string.find(string.rep('a', 100000), '.*b')]]
- -- wait (so script can reach the loop)
- assert(f:read() == "15")
- assert(os.execute("sleep 1"))
- -- must send at least two INT signals to stop this Lua script
- local n = 100
- for i = 0, 100 do -- keep sending signals
- if not kill(pid) then -- until it fails
- n = i -- number of non-failed kills
- break
- end
- end
- assert(f:close())
- assert(n >= 2)
- print(string.format("done (with %d kills)", n))
- end
- print("OK")
|