errors.lua 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. print("testing errors")
  2. function doit (s)
  3. local f, msg = loadstring(s)
  4. if f == nil then return msg end
  5. local cond, msg = pcall(f)
  6. return (not cond) and msg
  7. end
  8. function checkmessage (prog, msg)
  9. assert(string.find(doit(prog), msg, 1, true))
  10. end
  11. function checksyntax (prog, extra, token, line)
  12. local msg = doit(prog)
  13. token = string.gsub(token, "(%p)", "%%%1")
  14. local pt = string.format([[^%%[string ".*"%%]:%d: .- near '%s'$]],
  15. line, token)
  16. assert(string.find(msg, pt))
  17. assert(string.find(msg, msg, 1, true))
  18. end
  19. -- test error message with no extra info
  20. assert(doit("error('hi', 0)") == 'hi')
  21. -- test error message with no info
  22. assert(doit("error()") == nil)
  23. -- test common errors/errors that crashed in the past
  24. assert(doit("unpack({}, 1, n=2^30)"))
  25. assert(doit("a=math.sin()"))
  26. assert(not doit("tostring(1)") and doit("tostring()"))
  27. assert(doit"tonumber()")
  28. assert(doit"repeat until 1; a")
  29. checksyntax("break label", "", "label", 1)
  30. assert(doit";")
  31. assert(doit"a=1;;")
  32. assert(doit"return;;")
  33. assert(doit"assert(false)")
  34. assert(doit"assert(nil)")
  35. assert(doit"a=math.sin\n(3)")
  36. assert(doit("function a (... , ...) end"))
  37. assert(doit("function a (, ...) end"))
  38. checksyntax([[
  39. local a = {4
  40. ]], "'}' expected (to close '{' at line 1)", "<eof>", 3)
  41. -- tests for better error messages
  42. checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'")
  43. checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)",
  44. "local 'bbbb'")
  45. checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'")
  46. checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
  47. assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'"))
  48. checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number")
  49. aaa = nil
  50. checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
  51. checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
  52. checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
  53. checkmessage("local a,b,c; (function () a = b+1 end)()", "upvalue 'b'")
  54. assert(not doit"local aaa={bbb={ddd=next}}; aaa.bbb:ddd(nil)")
  55. checkmessage("b=1; local aaa='a'; x=aaa+b", "local 'aaa'")
  56. checkmessage("aaa={}; x=3/aaa", "global 'aaa'")
  57. checkmessage("aaa='2'; b=nil;x=aaa*b", "global 'b'")
  58. checkmessage("aaa={}; x=-aaa", "global 'aaa'")
  59. assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
  60. assert(not string.find(doit"aaa={}; (aaa or aaa)()", "'aaa'"))
  61. checkmessage([[aaa=9
  62. repeat until 3==3
  63. local x=math.sin(math.cos(3))
  64. if math.sin(1) == x then return math.sin(1) end -- tail call
  65. local a,b = 1, {
  66. {x='a'..'b'..'c', y='b', z=x},
  67. {1,2,3,4,5} or 3+3<=3+3,
  68. 3+1>3+1,
  69. {d = x and aaa[x or y]}}
  70. ]], "global 'aaa'")
  71. checkmessage([[
  72. local x,y = {},1
  73. if math.sin(1) == 0 then return 3 end -- return
  74. x.a()]], "field 'a'")
  75. checkmessage([[
  76. prefix = nil
  77. insert = nil
  78. while 1 do
  79. local a
  80. if nil then break end
  81. insert(prefix, a)
  82. end]], "global 'insert'")
  83. checkmessage([[ -- tail call
  84. return math.sin("a")
  85. ]], "'sin'")
  86. checkmessage([[collectgarbage("nooption")]], "invalid option")
  87. checkmessage([[x = print .. "a"]], "concatenate")
  88. checkmessage("getmetatable(io.stdin).__gc()", "no value")
  89. print'+'
  90. -- testing line error
  91. function lineerror (s)
  92. local err,msg = pcall(loadstring(s))
  93. local line = string.match(msg, ":(%d+):")
  94. return line and line+0
  95. end
  96. assert(lineerror"local a\n for i=1,'a' do \n print(i) \n end" == 2)
  97. assert(lineerror"\n local a \n for k,v in 3 \n do \n print(k) \n end" == 3)
  98. assert(lineerror"\n\n for k,v in \n 3 \n do \n print(k) \n end" == 4)
  99. assert(lineerror"function a.x.y ()\na=a+1\nend" == 1)
  100. local p = [[
  101. function g() f() end
  102. function f(x) error('a', X) end
  103. g()
  104. ]]
  105. X=3;assert(lineerror(p) == 3)
  106. X=0;assert(lineerror(p) == nil)
  107. X=1;assert(lineerror(p) == 2)
  108. X=2;assert(lineerror(p) == 1)
  109. lineerror = nil
  110. C = 0
  111. local l = debug.getinfo(1, "l").currentline; function y () C=C+1; y() end
  112. local function checkstackmessage (m)
  113. return (string.find(m, "^.-:%d+: stack overflow"))
  114. end
  115. assert(checkstackmessage(doit('y()')))
  116. assert(checkstackmessage(doit('y()')))
  117. assert(checkstackmessage(doit('y()')))
  118. -- teste de linhas em erro
  119. C = 0
  120. local l1
  121. local function g()
  122. l1 = debug.getinfo(1, "l").currentline; y()
  123. end
  124. local _, stackmsg = xpcall(g, debug.traceback)
  125. local stack = {}
  126. for line in string.gmatch(stackmsg, "[^\n]*") do
  127. local curr = string.match(line, ":(%d+):")
  128. if curr then table.insert(stack, tonumber(curr)) end
  129. end
  130. local i=1
  131. while stack[i] ~= l1 do
  132. assert(stack[i] == l)
  133. i = i+1
  134. end
  135. assert(i > 15)
  136. -- error in error handling
  137. local res, msg = xpcall(error, error)
  138. assert(not res and type(msg) == 'string')
  139. local function f (x)
  140. if x==0 then error('a\n')
  141. else
  142. local aux = function () return f(x-1) end
  143. local a,b = xpcall(aux, aux)
  144. return a,b
  145. end
  146. end
  147. f(3)
  148. -- non string messages
  149. function f() error{msg='x'} end
  150. res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end)
  151. assert(msg.msg == 'xy')
  152. print('+')
  153. checksyntax("syntax error", "", "error", 1)
  154. checksyntax("1.000", "", "1.000", 1)
  155. checksyntax("[[a]]", "", "[[a]]", 1)
  156. checksyntax("'aa'", "", "'aa'", 1)
  157. -- test 255 as first char in a chunk
  158. checksyntax("\255a = 1", "", "\255", 1)
  159. doit('I = loadstring("a=9+"); a=3')
  160. assert(a==3 and I == nil)
  161. print('+')
  162. lim = 1000
  163. if rawget(_G, "_soft") then lim = 100 end
  164. for i=1,lim do
  165. doit('a = ')
  166. doit('a = 4+nil')
  167. end
  168. -- testing syntax limits
  169. local function testrep (init, rep)
  170. local s = "local a; "..init .. string.rep(rep, 400)
  171. local a,b = loadstring(s)
  172. assert(not a and string.find(b, "syntax levels"))
  173. end
  174. testrep("a=", "{")
  175. testrep("a=", "(")
  176. testrep("", "a(")
  177. testrep("", "do ")
  178. testrep("", "while a do ")
  179. testrep("", "if a then else ")
  180. testrep("", "function foo () ")
  181. testrep("a=", "a..")
  182. testrep("a=", "a^")
  183. -- testing other limits
  184. -- upvalues
  185. local s = "function foo ()\n local "
  186. for j = 1,70 do
  187. s = s.."a"..j..", "
  188. end
  189. s = s.."b\n"
  190. for j = 1,70 do
  191. s = s.."function foo"..j.." ()\n a"..j.."=3\n"
  192. end
  193. local a,b = loadstring(s)
  194. assert(string.find(b, "line 3"))
  195. -- local variables
  196. s = "\nfunction foo ()\n local "
  197. for j = 1,300 do
  198. s = s.."a"..j..", "
  199. end
  200. s = s.."b\n"
  201. local a,b = loadstring(s)
  202. assert(string.find(b, "line 2"))
  203. print('OK')