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