Browse Source

New test file 'memerr.lua'

Tests for memory-allocation errors moved from 'api.lua' to this new
file, as 'api.lua' was already too big. (Besides, these tests have
nothing to do with the API.)
Roberto Ierusalimschy 11 months ago
parent
commit
4398e488e6
4 changed files with 268 additions and 243 deletions
  1. 1 0
      testes/all.lua
  2. 0 243
      testes/api.lua
  3. 266 0
      testes/memerr.lua
  4. 1 0
      testes/packtests

+ 1 - 0
testes/all.lua

@@ -182,6 +182,7 @@ dofile('nextvar.lua')
 dofile('pm.lua')
 dofile('utf8.lua')
 dofile('api.lua')
+dofile('memerr.lua')
 assert(dofile('events.lua') == 12)
 dofile('vararg.lua')
 dofile('closure.lua')

+ 0 - 243
testes/api.lua

@@ -11,9 +11,6 @@ local debug = require "debug"
 local pack = table.pack
 
 
--- standard error message for memory errors
-local MEMERRMSG = "not enough memory"
-
 local function tcheck (t1, t2)
   assert(t1.n == (t2.n or #t2) + 1)
   for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
@@ -432,11 +429,6 @@ do
       "bad argument #4 (string expected, got no value)")
 
 
-  -- memory error
-  T.totalmem(T.totalmem()+10000)   -- set low memory limit (+10k)
-  assert(T.checkpanic("newuserdata 20000") == MEMERRMSG)
-  T.totalmem(0)          -- restore high limit
-
   -- memory error + thread status
   local x = T.checkpanic(
     [[ alloccount 0    # force a memory error in next line
@@ -1306,241 +1298,6 @@ do
 end
 
 
---[[
-** {==================================================================
-** Testing memory limits
-** ===================================================================
---]]
-
-print("memory-allocation errors")
-
-checkerr("block too big", T.newuserdata, math.maxinteger)
-collectgarbage()
-local f = load"local a={}; for i=1,100000 do a[i]=i end"
-T.alloccount(10)
-checkerr(MEMERRMSG, f)
-T.alloccount()          -- remove limit
-
-
--- test memory errors; increase limit for maximum memory by steps,
--- o that we get memory errors in all allocations of a given
--- task, until there is enough memory to complete the task without
--- errors.
-local function testbytes (s, f)
-  collectgarbage()
-  local M = T.totalmem()
-  local oldM = M
-  local a,b = nil
-  while true do
-    collectgarbage(); collectgarbage()
-    T.totalmem(M)
-    a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
-    T.totalmem(0)  -- remove limit
-    if a and b == "OK" then break end       -- stop when no more errors
-    if b ~= "OK" and b ~= MEMERRMSG then    -- not a memory error?
-      error(a, 0)   -- propagate it
-    end
-    M = M + 7   -- increase memory limit
-  end
-  print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
-  return a
-end
-
--- test memory errors; increase limit for number of allocations one
--- by one, so that we get memory errors in all allocations of a given
--- task, until there is enough allocations to complete the task without
--- errors.
-
-local function testalloc (s, f)
-  collectgarbage()
-  local M = 0
-  local a,b = nil
-  while true do
-    collectgarbage(); collectgarbage()
-    T.alloccount(M)
-    a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
-    T.alloccount()  -- remove limit
-    if a and b == "OK" then break end       -- stop when no more errors
-    if b ~= "OK" and b ~= MEMERRMSG then    -- not a memory error?
-      error(a, 0)   -- propagate it
-    end
-    M = M + 1   -- increase allocation limit
-  end
-  print(string.format("minimum allocations for %s: %d allocations", s, M))
-  return a
-end
-
-
-local function testamem (s, f)
-  testalloc(s, f)
-  return testbytes(s, f)
-end
-
-
--- doing nothing
-b = testamem("doing nothing", function () return 10 end)
-assert(b == 10)
-
--- testing memory errors when creating a new state
-
-testamem("state creation", function ()
-  local st = T.newstate()
-  if st then T.closestate(st) end   -- close new state
-  return st
-end)
-
-testamem("empty-table creation", function ()
-  return {}
-end)
-
-testamem("string creation", function ()
-  return "XXX" .. "YYY"
-end)
-
-testamem("coroutine creation", function()
-           return coroutine.create(print)
-end)
-
-
--- testing to-be-closed variables
-testamem("to-be-closed variables", function()
-  local flag
-  do
-    local x <close> =
-              setmetatable({}, {__close = function () flag = true end})
-    flag = false
-    local x = {}
-  end
-  return flag
-end)
-
-
--- testing threads
-
--- get main thread from registry
-local mt = T.testC("rawgeti R !M; return 1")
-assert(type(mt) == "thread" and coroutine.running() == mt)
-
-
-
-local function expand (n,s)
-  if n==0 then return "" end
-  local e = string.rep("=", n)
-  return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
-                              e, s, expand(n-1,s), e)
-end
-
-G=0; collectgarbage(); a =collectgarbage("count")
-load(expand(20,"G=G+1"))()
-assert(G==20); collectgarbage();  -- assert(gcinfo() <= a+1)
-G = nil
-
-testamem("running code on new thread", function ()
-  return T.doonnewstack("local x=1") == 0  -- try to create thread
-end)
-
-
--- testing memory x compiler
-
-testamem("loadstring", function ()
-  return load("x=1")  -- try to do load a string
-end)
-
-
-local testprog = [[
-local function foo () return end
-local t = {"x"}
-AA = "aaa"
-for i = 1, #t do AA = AA .. t[i] end
-return true
-]]
-
--- testing memory x dofile
-_G.AA = nil
-local t =os.tmpname()
-local f = assert(io.open(t, "w"))
-f:write(testprog)
-f:close()
-testamem("dofile", function ()
-  local a = loadfile(t)
-  return a and a()
-end)
-assert(os.remove(t))
-assert(_G.AA == "aaax")
-
-
--- other generic tests
-
-testamem("gsub", function ()
-  local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
-  return (a == 'ablo ablo')
-end)
-
-testamem("dump/undump", function ()
-  local a = load(testprog)
-  local b = a and string.dump(a)
-  a = b and load(b)
-  return a and a()
-end)
-
-_G.AA = nil
-
-local t = os.tmpname()
-testamem("file creation", function ()
-  local f = assert(io.open(t, 'w'))
-  assert (not io.open"nomenaoexistente")
-  io.close(f);
-  return not loadfile'nomenaoexistente'
-end)
-assert(os.remove(t))
-
-testamem("table creation", function ()
-  local a, lim = {}, 10
-  for i=1,lim do a[i] = i; a[i..'a'] = {} end
-  return (type(a[lim..'a']) == 'table' and a[lim] == lim)
-end)
-
-testamem("constructors", function ()
-  local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5}
-  return (type(a) == 'table' and a.e == 5)
-end)
-
-local a = 1
-local close = nil
-testamem("closure creation", function ()
-  function close (b)
-   return function (x) return b + x end
-  end
-  return (close(2)(4) == 6)
-end)
-
-testamem("using coroutines", function ()
-  local a = coroutine.wrap(function ()
-              coroutine.yield(string.rep("a", 10))
-              return {}
-            end)
-  assert(string.len(a()) == 10)
-  return a()
-end)
-
-do   -- auxiliary buffer
-  local lim = 100
-  local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end
-  testamem("auxiliary buffer", function ()
-    return (#table.concat(a, ",") == 20*lim + lim - 1)
-  end)
-end
-
-testamem("growing stack", function ()
-  local function foo (n)
-    if n == 0 then return 1 else return 1 + foo(n - 1) end
-  end
-  return foo(100)
-end)
-
--- }==================================================================
-
-
 do   -- testing failing in 'lua_checkstack'
   local res = T.testC([[rawcheckstack 500000; return 1]])
   assert(res == false)

+ 266 - 0
testes/memerr.lua

@@ -0,0 +1,266 @@
+-- $Id: testes/memerr.lua $
+-- See Copyright Notice in file all.lua
+
+
+local function checkerr (msg, f, ...)
+  local stat, err = pcall(f, ...)
+  assert(not stat and string.find(err, msg))
+end
+
+if T==nil then
+  (Message or print)
+      ('\n >>> testC not active: skipping memory error tests <<<\n')
+  return
+end
+
+print("testing memory-allocation errors")
+
+local debug = require "debug"
+
+local pack = table.pack
+
+-- standard error message for memory errors
+local MEMERRMSG = "not enough memory"
+
+
+-- memory error in panic function
+T.totalmem(T.totalmem()+10000)   -- set low memory limit (+10k)
+assert(T.checkpanic("newuserdata 20000") == MEMERRMSG)
+T.totalmem(0)          -- restore high limit
+
+
+
+-- {==================================================================
+-- Testing memory limits
+-- ===================================================================
+
+checkerr("block too big", T.newuserdata, math.maxinteger)
+collectgarbage()
+local f = load"local a={}; for i=1,100000 do a[i]=i end"
+T.alloccount(10)
+checkerr(MEMERRMSG, f)
+T.alloccount()          -- remove limit
+
+
+-- test memory errors; increase limit for maximum memory by steps,
+-- o that we get memory errors in all allocations of a given
+-- task, until there is enough memory to complete the task without
+-- errors.
+local function testbytes (s, f)
+  collectgarbage()
+  local M = T.totalmem()
+  local oldM = M
+  local a,b = nil
+  while true do
+    collectgarbage(); collectgarbage()
+    T.totalmem(M)
+    a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
+    T.totalmem(0)  -- remove limit
+    if a and b == "OK" then break end       -- stop when no more errors
+    if b ~= "OK" and b ~= MEMERRMSG then    -- not a memory error?
+      error(a, 0)   -- propagate it
+    end
+    M = M + 7   -- increase memory limit
+  end
+  print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
+  return a
+end
+
+-- test memory errors; increase limit for number of allocations one
+-- by one, so that we get memory errors in all allocations of a given
+-- task, until there is enough allocations to complete the task without
+-- errors.
+
+local function testalloc (s, f)
+  collectgarbage()
+  local M = 0
+  local a,b = nil
+  while true do
+    collectgarbage(); collectgarbage()
+    T.alloccount(M)
+    a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
+    T.alloccount()  -- remove limit
+    if a and b == "OK" then break end       -- stop when no more errors
+    if b ~= "OK" and b ~= MEMERRMSG then    -- not a memory error?
+      error(a, 0)   -- propagate it
+    end
+    M = M + 1   -- increase allocation limit
+  end
+  print(string.format("minimum allocations for %s: %d allocations", s, M))
+  return a
+end
+
+
+local function testamem (s, f)
+  testalloc(s, f)
+  return testbytes(s, f)
+end
+
+
+-- doing nothing
+b = testamem("doing nothing", function () return 10 end)
+assert(b == 10)
+
+-- testing memory errors when creating a new state
+
+testamem("state creation", function ()
+  local st = T.newstate()
+  if st then T.closestate(st) end   -- close new state
+  return st
+end)
+
+testamem("empty-table creation", function ()
+  return {}
+end)
+
+testamem("string creation", function ()
+  return "XXX" .. "YYY"
+end)
+
+testamem("coroutine creation", function()
+           return coroutine.create(print)
+end)
+
+
+-- testing to-be-closed variables
+testamem("to-be-closed variables", function()
+  local flag
+  do
+    local x <close> =
+              setmetatable({}, {__close = function () flag = true end})
+    flag = false
+    local x = {}
+  end
+  return flag
+end)
+
+
+-- testing threads
+
+-- get main thread from registry
+local mt = T.testC("rawgeti R !M; return 1")
+assert(type(mt) == "thread" and coroutine.running() == mt)
+
+
+
+local function expand (n,s)
+  if n==0 then return "" end
+  local e = string.rep("=", n)
+  return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
+                              e, s, expand(n-1,s), e)
+end
+
+G=0; collectgarbage(); a =collectgarbage("count")
+load(expand(20,"G=G+1"))()
+assert(G==20); collectgarbage();  -- assert(gcinfo() <= a+1)
+G = nil
+
+testamem("running code on new thread", function ()
+  return T.doonnewstack("local x=1") == 0  -- try to create thread
+end)
+
+
+-- testing memory x compiler
+
+testamem("loadstring", function ()
+  return load("x=1")  -- try to do load a string
+end)
+
+
+local testprog = [[
+local function foo () return end
+local t = {"x"}
+AA = "aaa"
+for i = 1, #t do AA = AA .. t[i] end
+return true
+]]
+
+-- testing memory x dofile
+_G.AA = nil
+local t =os.tmpname()
+local f = assert(io.open(t, "w"))
+f:write(testprog)
+f:close()
+testamem("dofile", function ()
+  local a = loadfile(t)
+  return a and a()
+end)
+assert(os.remove(t))
+assert(_G.AA == "aaax")
+
+
+-- other generic tests
+
+testamem("gsub", function ()
+  local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
+  return (a == 'ablo ablo')
+end)
+
+testamem("dump/undump", function ()
+  local a = load(testprog)
+  local b = a and string.dump(a)
+  a = b and load(b)
+  return a and a()
+end)
+
+_G.AA = nil
+
+local t = os.tmpname()
+testamem("file creation", function ()
+  local f = assert(io.open(t, 'w'))
+  assert (not io.open"nomenaoexistente")
+  io.close(f);
+  return not loadfile'nomenaoexistente'
+end)
+assert(os.remove(t))
+
+testamem("table creation", function ()
+  local a, lim = {}, 10
+  for i=1,lim do a[i] = i; a[i..'a'] = {} end
+  return (type(a[lim..'a']) == 'table' and a[lim] == lim)
+end)
+
+testamem("constructors", function ()
+  local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5}
+  return (type(a) == 'table' and a.e == 5)
+end)
+
+local a = 1
+local close = nil
+testamem("closure creation", function ()
+  function close (b)
+   return function (x) return b + x end
+  end
+  return (close(2)(4) == 6)
+end)
+
+testamem("using coroutines", function ()
+  local a = coroutine.wrap(function ()
+              coroutine.yield(string.rep("a", 10))
+              return {}
+            end)
+  assert(string.len(a()) == 10)
+  return a()
+end)
+
+do   -- auxiliary buffer
+  local lim = 100
+  local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end
+  testamem("auxiliary buffer", function ()
+    return (#table.concat(a, ",") == 20*lim + lim - 1)
+  end)
+end
+
+testamem("growing stack", function ()
+  local function foo (n)
+    if n == 0 then return 1 else return 1 + foo(n - 1) end
+  end
+  return foo(100)
+end)
+
+-- }==================================================================
+
+
+print "Ok"
+
+

+ 1 - 0
testes/packtests

@@ -28,6 +28,7 @@ $NAME/literals.lua  \
 $NAME/locals.lua  \
 $NAME/main.lua  \
 $NAME/math.lua  \
+$NAME/memerr.lua  \
 $NAME/nextvar.lua  \
 $NAME/pm.lua  \
 $NAME/sort.lua  \