~soapdog/lua

90044a6597494fa9a2a4a1b992b050bb0e66edb8 — Andre Alves Garzia 1 year, 5 months ago fe2964f
adding tests
106 files changed, 32466 insertions(+), 0 deletions(-)

A test-all.bat
A test-version.bat
A tests/5.1.5/README
A tests/5.1.5/all.lua
A tests/5.1.5/api.lua
A tests/5.1.5/attrib.lua
A tests/5.1.5/basic.bat
A tests/5.1.5/big.lua
A tests/5.1.5/calls.lua
A tests/5.1.5/checktable.lua
A tests/5.1.5/closure.lua
A tests/5.1.5/code.lua
A tests/5.1.5/constructs.lua
A tests/5.1.5/db.lua
A tests/5.1.5/errors.lua
A tests/5.1.5/etc/ltests.c
A tests/5.1.5/etc/ltests.h
A tests/5.1.5/events.lua
A tests/5.1.5/files.lua
A tests/5.1.5/gc.lua
A tests/5.1.5/libs/lib1.c
A tests/5.1.5/libs/lib11.c
A tests/5.1.5/libs/lib2.c
A tests/5.1.5/libs/lib21.c
A tests/5.1.5/libs/makefile
A tests/5.1.5/literals.lua
A tests/5.1.5/locals.lua
A tests/5.1.5/main.lua
A tests/5.1.5/math.lua
A tests/5.1.5/nextvar.lua
A tests/5.1.5/pm.lua
A tests/5.1.5/sort.lua
A tests/5.1.5/strings.lua
A tests/5.1.5/vararg.lua
A tests/5.1.5/verybig.lua
A tests/5.2.4/all.lua
A tests/5.2.4/api.lua
A tests/5.2.4/attrib.lua
A tests/5.2.4/basic.bat
A tests/5.2.4/big.lua
A tests/5.2.4/bitwise.lua
A tests/5.2.4/calls.lua
A tests/5.2.4/checktable.lua
A tests/5.2.4/closure.lua
A tests/5.2.4/code.lua
A tests/5.2.4/constructs.lua
A tests/5.2.4/coroutine.lua
A tests/5.2.4/db.lua
A tests/5.2.4/errors.lua
A tests/5.2.4/events.lua
A tests/5.2.4/files.lua
A tests/5.2.4/gc.lua
A tests/5.2.4/goto.lua
A tests/5.2.4/libs/lib1.c
A tests/5.2.4/libs/lib11.c
A tests/5.2.4/libs/lib2.c
A tests/5.2.4/libs/lib21.c
A tests/5.2.4/libs/makefile
A tests/5.2.4/literals.lua
A tests/5.2.4/locals.lua
A tests/5.2.4/ltests/ltests.c
A tests/5.2.4/ltests/ltests.h
A tests/5.2.4/main.lua
A tests/5.2.4/math.lua
A tests/5.2.4/nextvar.lua
A tests/5.2.4/pm.lua
A tests/5.2.4/sort.lua
A tests/5.2.4/strings.lua
A tests/5.2.4/vararg.lua
A tests/5.2.4/verybig.lua
A tests/5.3.5/all.lua
A tests/5.3.5/api.lua
A tests/5.3.5/attrib.lua
A tests/5.3.5/basic.bat
A tests/5.3.5/big.lua
A tests/5.3.5/bitwise.lua
A tests/5.3.5/calls.lua
A tests/5.3.5/closure.lua
A tests/5.3.5/code.lua
A tests/5.3.5/constructs.lua
A tests/5.3.5/coroutine.lua
A tests/5.3.5/db.lua
A tests/5.3.5/errors.lua
A tests/5.3.5/events.lua
A tests/5.3.5/files.lua
A tests/5.3.5/gc.lua
A tests/5.3.5/goto.lua
A tests/5.3.5/libs/lib1.c
A tests/5.3.5/libs/lib11.c
A tests/5.3.5/libs/lib2.c
A tests/5.3.5/libs/lib21.c
A tests/5.3.5/libs/makefile
A tests/5.3.5/literals.lua
A tests/5.3.5/locals.lua
A tests/5.3.5/ltests/ltests.c
A tests/5.3.5/ltests/ltests.h
A tests/5.3.5/main.lua
A tests/5.3.5/math.lua
A tests/5.3.5/nextvar.lua
A tests/5.3.5/pm.lua
A tests/5.3.5/sort.lua
A tests/5.3.5/strings.lua
A tests/5.3.5/tpack.lua
A tests/5.3.5/utf8.lua
A tests/5.3.5/vararg.lua
A tests/5.3.5/verybig.lua
A test-all.bat => test-all.bat +38 -0
@@ 0,0 1,38 @@
@echo off


echo ****************************************************
echo * This script only executes tests on arm64 and x86
echo * because those are the only versions that run
echo * on an arm64 machine.
echo ***************************************************

echo Testing Lua 5.3.5 ...

set /p dummy=Press ENTER to test for ARM64 ...
call test-version.bat 5.3.5 arm64

set /p dummy=Press ENTER to test for x86 ...
call test-version.bat 5.3.5 x86

REM ---------------------------------------------------

echo Testing Lua 5.2.5 ...

set /p dummy=Press ENTER to test for ARM64 ...
call test-version.bat 5.2.4 arm64

set /p dummy=Press ENTER to test for x86 ...
call test-version.bat 5.2.4 x86

REM ---------------------------------------------------

echo Testing Lua 5.1.5 ...

set /p dummy=Press ENTER to test for ARM64 ...
call test-version.bat 5.1.5 arm64

set /p dummy=Press ENTER to test for x86 ...
call test-version.bat 5.1.5 x86

REM ---------------------------------------------------
\ No newline at end of file

A test-version.bat => test-version.bat +31 -0
@@ 0,0 1,31 @@
@echo off

REM *************************************************
REM * Lua test script for Windows 10
REM *************************************************

set LUA_VERSION=%1
set ARCH=%2
set BUILD_FOLDER=dist\%LUA_VERSION%\%ARCH%
set TEST_FOLDER=tests\%LUA_VERSION%


if not exist %BUILD_FOLDER% goto :not_found

echo basic test for ARM64 ...

cd %TEST_FOLDER%

set LUA=%BUILD_FOLDER%\lua.exe

call basic.bat 

goto :exit 

:not_found

echo can't find %BUILD_FOLDER%

:exit

 cd ..\..
\ No newline at end of file

A tests/5.1.5/README => tests/5.1.5/README +41 -0
@@ 0,0 1,41 @@
This tarball contains the official test scripts for Lua 5.1.
Unlike Lua itself, these tests do not aim portability, small footprint,
or easy of use. (Their main goal is to try to crash Lua.) They are not
intended for general use. You are wellcome to use them, but expect to
have to "dirt your hands".

The tarball should expand in the following contents:
  - several .lua scripts with the tests
  - a main "all.lua" Lua script that invokes all the other scripts
  - a subdirectory "libs" with an empty subdirectory "libs/P1",
    to be used by the scripts
  - a subdirectory "etc" with some extra files

To run the tests, do as follows:

- go to the test directory

- set LUA_PATH to "?;./?.lua" (or, better yet, set LUA_PATH to "./?.lua;;"
  and LUA_INIT to "package.path = '?;'..package.path")

- run "lua all.lua"


--------------------------------------------
Internal tests
--------------------------------------------

Some tests need a special library, "testC", that gives access to
several internal structures in Lua.
This library is only available when Lua is compiled in debug mode.
The scripts automatically detect its absence and skip those tests.

If you want to run these tests, move etc/ltests.c and etc/ltests.h to
the directory with the source Lua files, and recompile Lua with
the option -DLUA_USER_H='"ltests.h"' (or its equivalent to define
LUA_USER_H as the string "ltests.h", including the quotes). This
option not only adds the testC library, but it adds several other
internal tests as well. After the recompilation, run the tests
as before.



A tests/5.1.5/all.lua => tests/5.1.5/all.lua +137 -0
@@ 0,0 1,137 @@
#!../lua

math.randomseed(0)

collectgarbage("setstepmul", 180)
collectgarbage("setpause", 190)


--[=[
  example of a long [comment],
  [[spanning several [lines]]]

]=]

print("current path:\n  " .. string.gsub(package.path, ";", "\n  "))


local msgs = {}
function Message (m)
  print(m)
  msgs[#msgs+1] = string.sub(m, 3, -3)
end


local c = os.clock()

assert(os.setlocale"C")

local T,print,gcinfo,format,write,assert,type =
      T,print,gcinfo,string.format,io.write,assert,type

local function formatmem (m)
  if m < 1024 then return m
  else
    m = m/1024 - m/1024%1
    if m < 1024 then return m.."K"
    else
      m = m/1024 - m/1024%1
      return m.."M"
    end
  end
end

local showmem = function ()
  if not T then
    print(format("    ---- total memory: %s ----\n", formatmem(gcinfo())))
  else
    T.checkmemory()
    local a,b,c = T.totalmem()
    local d,e = gcinfo()
    print(format(
  "\n    ---- total memory: %s (%dK), max use: %s,  blocks: %d\n",
                        formatmem(a),  d,      formatmem(c),           b))
  end
end


--
-- redefine dofile to run files through dump/undump
--
dofile = function (n)
  showmem()
  local f = assert(loadfile(n))
  local b = string.dump(f)
  f = assert(loadstring(b))
  return f()
end

dofile('main.lua')

do
  local u = newproxy(true)
  local newproxy, stderr = newproxy, io.stderr
  getmetatable(u).__gc = function (o)
    stderr:write'.'
    newproxy(o)
  end
end

local f = assert(loadfile('gc.lua'))
f()
dofile('db.lua')
assert(dofile('calls.lua') == deep and deep)
dofile('strings.lua')
dofile('literals.lua')
assert(dofile('attrib.lua') == 27)
assert(dofile('locals.lua') == 5)
dofile('constructs.lua')
dofile('code.lua')
do
  local f = coroutine.wrap(assert(loadfile('big.lua')))
  assert(f() == 'b')
  assert(f() == 'a')
end
dofile('nextvar.lua')
dofile('pm.lua')
dofile('api.lua')
assert(dofile('events.lua') == 12)
dofile('vararg.lua')
dofile('closure.lua')
dofile('errors.lua')
dofile('math.lua')
dofile('sort.lua')
assert(dofile('verybig.lua') == 10); collectgarbage()
dofile('files.lua')

if #msgs > 0 then
  print("\ntests not performed:")
  for i=1,#msgs do
    print(msgs[i])
  end
  print()
end

print("final OK !!!")
print('cleaning all!!!!')

debug.sethook(function (a) assert(type(a) == 'string') end, "cr")

local _G, collectgarbage, showmem, print, format, clock =
      _G, collectgarbage, showmem, print, format, os.clock

local a={}
for n in pairs(_G) do a[n] = 1 end
a.tostring = nil
a.___Glob = nil
for n in pairs(a) do _G[n] = nil end

a = nil
collectgarbage()
collectgarbage()
collectgarbage()
collectgarbage()
collectgarbage()
collectgarbage();showmem()

print(format("\n\ntotal time: %.2f\n", clock()-c))

A tests/5.1.5/api.lua => tests/5.1.5/api.lua +711 -0
@@ 0,0 1,711 @@

if T==nil then
  (Message or print)('\a\n >>> testC not active: skipping API tests <<<\n\a')
  return
end



function tcheck (t1, t2)
  table.remove(t1, 1)  -- remove code
  assert(table.getn(t1) == table.getn(t2))
  for i=1,table.getn(t1) do assert(t1[i] == t2[i]) end
end

function pack(...) return arg end


print('testing C API')

-- testing allignment
a = T.d2s(12458954321123)
assert(string.len(a) == 8)   -- sizeof(double)
assert(T.s2d(a) == 12458954321123)

a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
assert(a == 2 and b == 3 and not c)

-- test that all trues are equal
a,b,c = T.testC("pushbool 1; pushbool 2; pushbool 0; return 3")
assert(a == b and a == true and c == false)
a,b,c = T.testC"pushbool 0; pushbool 10; pushnil;\
                      tobool -3; tobool -3; tobool -3; return 3"
assert(a==0 and b==1 and c==0)


a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40)
assert(a == 40 and b == 5 and not c)

t = pack(T.testC("settop 5; gettop; return .", 2, 3))
tcheck(t, {n=4,2,3})

t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23))
assert(t.n == 10 and t[1] == nil and t[10] == nil)

t = pack(T.testC("remove -2; gettop; return .", 2, 3, 4))
tcheck(t, {n=2,2,4})

t = pack(T.testC("insert -1; gettop; return .", 2, 3))
tcheck(t, {n=2,2,3})

t = pack(T.testC("insert 3; gettop; return .", 2, 3, 4, 5))
tcheck(t, {n=4,2,5,3,4})

t = pack(T.testC("replace 2; gettop; return .", 2, 3, 4, 5))
tcheck(t, {n=3,5,3,4})

t = pack(T.testC("replace -2; gettop; return .", 2, 3, 4, 5))
tcheck(t, {n=3,2,3,5})

t = pack(T.testC("remove 3; gettop; return .", 2, 3, 4, 5))
tcheck(t, {n=3,2,4,5})

t = pack(T.testC("insert 3; pushvalue 3; remove 3; pushvalue 2; remove 2; \
                  insert 2; pushvalue 1; remove 1; insert 1; \
      insert -2; pushvalue -2; remove -3; gettop; return .",
      2, 3, 4, 5, 10, 40, 90))
tcheck(t, {n=7,2,3,4,5,10,40,90})

t = pack(T.testC("concat 5; gettop; return .", "alo", 2, 3, "joao", 12))
tcheck(t, {n=1,"alo23joao12"})

-- testing MULTRET
t = pack(T.testC("rawcall 2,-1; gettop; return .",
     function (a,b) return 1,2,3,4,a,b end, "alo", "joao"))
tcheck(t, {n=6,1,2,3,4,"alo", "joao"})

do  -- test returning more results than fit in the caller stack
  local a = {}
  for i=1,1000 do a[i] = true end; a[999] = 10
  local b = T.testC([[call 1 -1; pop 1; tostring -1; return 1]], unpack, a)
  assert(b == "10")
end


-- testing lessthan
assert(T.testC("lessthan 2 5, return 1", 3, 2, 2, 4, 2, 2))
assert(T.testC("lessthan 5 2, return 1", 4, 2, 2, 3, 2, 2))
assert(not T.testC("lessthan 2 -3, return 1", "4", "2", "2", "3", "2", "2"))
assert(not T.testC("lessthan -3 2, return 1", "3", "2", "2", "4", "2", "2"))

local b = {__lt = function (a,b) return a[1] < b[1] end}
local a1,a3,a4 = setmetatable({1}, b),
                 setmetatable({3}, b),
                 setmetatable({4}, b)
assert(T.testC("lessthan 2 5, return 1", a3, 2, 2, a4, 2, 2))
assert(T.testC("lessthan 5 -6, return 1", a4, 2, 2, a3, 2, 2))
a,b = T.testC("lessthan 5 -6, return 2", a1, 2, 2, a3, 2, 20)
assert(a == 20 and b == false)


-- testing lua_is

function count (x, n)
  n = n or 2
  local prog = [[
    isnumber %d;
    isstring %d;
    isfunction %d;
    iscfunction %d;
    istable %d;
    isuserdata %d;
    isnil %d;
    isnull %d;
    return 8
  ]]
  prog = string.format(prog, n, n, n, n, n, n, n, n)
  local a,b,c,d,e,f,g,h = T.testC(prog, x)
  return a+b+c+d+e+f+g+(100*h)
end

assert(count(3) == 2)
assert(count('alo') == 1)
assert(count('32') == 2)
assert(count({}) == 1)
assert(count(print) == 2)
assert(count(function () end) == 1)
assert(count(nil) == 1)
assert(count(io.stdin) == 1)
assert(count(nil, 15) == 100)

-- testing lua_to...

function to (s, x, n)
  n = n or 2
  return T.testC(string.format("%s %d; return 1", s, n), x)
end

assert(to("tostring", {}) == nil)
assert(to("tostring", "alo") == "alo")
assert(to("tostring", 12) == "12")
assert(to("tostring", 12, 3) == nil)
assert(to("objsize", {}) == 0)
assert(to("objsize", "alo\0\0a") == 6)
assert(to("objsize", T.newuserdata(0)) == 0)
assert(to("objsize", T.newuserdata(101)) == 101)
assert(to("objsize", 12) == 2)
assert(to("objsize", 12, 3) == 0)
assert(to("tonumber", {}) == 0)
assert(to("tonumber", "12") == 12)
assert(to("tonumber", "s2") == 0)
assert(to("tonumber", 1, 20) == 0)
a = to("tocfunction", math.deg)
assert(a(3) == math.deg(3) and a ~= math.deg)


-- testing errors

a = T.testC([[
  loadstring 2; call 0,1;
  pushvalue 3; insert -2; call 1, 1;
  call 0, 0;
  return 1
]], "x=150", function (a) assert(a==nil); return 3 end)

assert(type(a) == 'string' and x == 150)

function check3(p, ...)
  assert(arg.n == 3)
  assert(string.find(arg[3], p))
end
check3(":1:", T.testC("loadstring 2; gettop; return .", "x="))
check3("cannot read", T.testC("loadfile 2; gettop; return .", "."))
check3("cannot open xxxx", T.testC("loadfile 2; gettop; return .", "xxxx"))

-- testing table access

a = {x=0, y=12}
x, y = T.testC("gettable 2; pushvalue 4; gettable 2; return 2",
                a, 3, "y", 4, "x")
assert(x == 0 and y == 12)
T.testC("settable -5", a, 3, 4, "x", 15)
assert(a.x == 15)
a[a] = print
x = T.testC("gettable 2; return 1", a)  -- table and key are the same object!
assert(x == print)
T.testC("settable 2", a, "x")    -- table and key are the same object!
assert(a[a] == "x")

b = setmetatable({p = a}, {})
getmetatable(b).__index = function (t, i) return t.p[i] end
k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
assert(x == 15 and k == 35)
getmetatable(b).__index = function (t, i) return a[i] end
getmetatable(b).__newindex = function (t, i,v ) a[i] = v end
y = T.testC("insert 2; gettable -5; return 1", 2, 3, 4, "y", b)
assert(y == 12)
k = T.testC("settable -5, return 1", b, 3, 4, "x", 16)
assert(a.x == 16 and k == 4)
a[b] = 'xuxu'
y = T.testC("gettable 2, return 1", b)
assert(y == 'xuxu')
T.testC("settable 2", b, 19)
assert(a[b] == 19)

-- testing next
a = {}
t = pack(T.testC("next; gettop; return .", a, nil))
tcheck(t, {n=1,a})
a = {a=3}
t = pack(T.testC("next; gettop; return .", a, nil))
tcheck(t, {n=3,a,'a',3})
t = pack(T.testC("next; pop 1; next; gettop; return .", a, nil))
tcheck(t, {n=1,a})



-- testing upvalues

do
  local A = T.testC[[ pushnum 10; pushnum 20; pushcclosure 2; return 1]]
  t, b, c = A([[pushvalue U0; pushvalue U1; pushvalue U2; return 3]])
  assert(b == 10 and c == 20 and type(t) == 'table')
  a, b = A([[tostring U3; tonumber U4; return 2]])
  assert(a == nil and b == 0)
  A([[pushnum 100; pushnum 200; replace U2; replace U1]])
  b, c = A([[pushvalue U1; pushvalue U2; return 2]])
  assert(b == 100 and c == 200)
  A([[replace U2; replace U1]], {x=1}, {x=2})
  b, c = A([[pushvalue U1; pushvalue U2; return 2]])
  assert(b.x == 1 and c.x == 2)
  T.checkmemory()
end

local f = T.testC[[ pushnum 10; pushnum 20; pushcclosure 2; return 1]]
assert(T.upvalue(f, 1) == 10 and
       T.upvalue(f, 2) == 20 and
       T.upvalue(f, 3) == nil)
T.upvalue(f, 2, "xuxu")
assert(T.upvalue(f, 2) == "xuxu")


-- testing environments

assert(T.testC"pushvalue G; return 1" == _G)
assert(T.testC"pushvalue E; return 1" == _G)
local a = {}
T.testC("replace E; return 1", a)
assert(T.testC"pushvalue G; return 1" == _G)
assert(T.testC"pushvalue E; return 1" == a)
assert(debug.getfenv(T.testC) == a)
assert(debug.getfenv(T.upvalue) == _G)
-- userdata inherit environment
local u = T.testC"newuserdata 0; return 1"
assert(debug.getfenv(u) == a)
-- functions inherit environment
u = T.testC"pushcclosure 0; return 1"
assert(debug.getfenv(u) == a)
debug.setfenv(T.testC, _G)
assert(T.testC"pushvalue E; return 1" == _G)

local b = newproxy()
assert(debug.getfenv(b) == _G)
assert(debug.setfenv(b, a))
assert(debug.getfenv(b) == a)



-- testing locks (refs)

-- reuse of references
local i = T.ref{}
T.unref(i)
assert(T.ref{} == i)

Arr = {}
Lim = 100
for i=1,Lim do   -- lock many objects
  Arr[i] = T.ref({})
end

assert(T.ref(nil) == -1 and T.getref(-1) == nil)
T.unref(-1); T.unref(-1)

for i=1,Lim do   -- unlock all them
  T.unref(Arr[i])
end

function printlocks ()
  local n = T.testC("gettable R; return 1", "n")
  print("n", n)
  for i=0,n do
    print(i, T.testC("gettable R; return 1", i))
  end
end


for i=1,Lim do   -- lock many objects
  Arr[i] = T.ref({})
end

for i=1,Lim,2 do   -- unlock half of them
  T.unref(Arr[i])
end

assert(type(T.getref(Arr[2])) == 'table')


assert(T.getref(-1) == nil)


a = T.ref({})

collectgarbage()

assert(type(T.getref(a)) == 'table')


-- colect in cl the `val' of all collected userdata
tt = {}
cl = {n=0}
A = nil; B = nil
local F
F = function (x)
  local udval = T.udataval(x)
  table.insert(cl, udval)
  local d = T.newuserdata(100)   -- cria lixo
  d = nil
  assert(debug.getmetatable(x).__gc == F)
  loadstring("table.insert({}, {})")()   -- cria mais lixo
  collectgarbage()   -- forca coleta de lixo durante coleta!
  assert(debug.getmetatable(x).__gc == F)   -- coleta anterior nao melou isso?
  local dummy = {}    -- cria lixo durante coleta
  if A ~= nil then
    assert(type(A) == "userdata")
    assert(T.udataval(A) == B)
    debug.getmetatable(A)    -- just acess it
  end
  A = x   -- ressucita userdata
  B = udval
  return 1,2,3
end
tt.__gc = F

-- test whether udate collection frees memory in the right time
do
  collectgarbage();
  collectgarbage();
  local x = collectgarbage("count");
  local a = T.newuserdata(5001)
  assert(T.testC("objsize 2; return 1", a) == 5001)
  assert(collectgarbage("count") >= x+4) 
  a = nil
  collectgarbage();
  assert(collectgarbage("count") <= x+1)
  -- udata without finalizer
  x = collectgarbage("count")
  collectgarbage("stop")
  for i=1,1000 do newproxy(false) end
  assert(collectgarbage("count") > x+10)
  collectgarbage()
  assert(collectgarbage("count") <= x+1)
  -- udata with finalizer
  x = collectgarbage("count")
  collectgarbage()
  collectgarbage("stop")
  a = newproxy(true)
  getmetatable(a).__gc = function () end
  for i=1,1000 do newproxy(a) end
  assert(collectgarbage("count") >= x+10)
  collectgarbage()  -- this collection only calls TM, without freeing memory
  assert(collectgarbage("count") >= x+10)
  collectgarbage()  -- now frees memory
  assert(collectgarbage("count") <= x+1)
end


collectgarbage("stop")

-- create 3 userdatas with tag `tt'
a = T.newuserdata(0); debug.setmetatable(a, tt); na = T.udataval(a)
b = T.newuserdata(0); debug.setmetatable(b, tt); nb = T.udataval(b)
c = T.newuserdata(0); debug.setmetatable(c, tt); nc = T.udataval(c)

-- create userdata without meta table
x = T.newuserdata(4)
y = T.newuserdata(0)

assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)

d=T.ref(a);
e=T.ref(b);
f=T.ref(c);
t = {T.getref(d), T.getref(e), T.getref(f)}
assert(t[1] == a and t[2] == b and t[3] == c)

t=nil; a=nil; c=nil;
T.unref(e); T.unref(f)

collectgarbage()

-- check that unref objects have been collected
assert(table.getn(cl) == 1 and cl[1] == nc)

x = T.getref(d)
assert(type(x) == 'userdata' and debug.getmetatable(x) == tt)
x =nil
tt.b = b  -- create cycle
tt=nil    -- frees tt for GC
A = nil
b = nil
T.unref(d);
n5 = T.newuserdata(0)
debug.setmetatable(n5, {__gc=F})
n5 = T.udataval(n5)
collectgarbage()
assert(table.getn(cl) == 4)
-- check order of collection
assert(cl[2] == n5 and cl[3] == nb and cl[4] == na)


a, na = {}, {}
for i=30,1,-1 do
  a[i] = T.newuserdata(0)
  debug.setmetatable(a[i], {__gc=F})
  na[i] = T.udataval(a[i])
end
cl = {}
a = nil; collectgarbage()
assert(table.getn(cl) == 30)
for i=1,30 do assert(cl[i] == na[i]) end
na = nil


for i=2,Lim,2 do   -- unlock the other half
  T.unref(Arr[i])
end

x = T.newuserdata(41); debug.setmetatable(x, {__gc=F})
assert(T.testC("objsize 2; return 1", x) == 41)
cl = {}
a = {[x] = 1}
x = T.udataval(x)
collectgarbage()
-- old `x' cannot be collected (`a' still uses it)
assert(table.getn(cl) == 0)
for n in pairs(a) do a[n] = nil end
collectgarbage()
assert(table.getn(cl) == 1 and cl[1] == x)   -- old `x' must be collected

-- testing lua_equal
assert(T.testC("equal 2 4; return 1", print, 1, print, 20))
assert(T.testC("equal 3 2; return 1", 'alo', "alo"))
assert(T.testC("equal 2 3; return 1", nil, nil))
assert(not T.testC("equal 2 3; return 1", {}, {}))
assert(not T.testC("equal 2 3; return 1"))
assert(not T.testC("equal 2 3; return 1", 3))

-- testing lua_equal with fallbacks
do
  local map = {}
  local t = {__eq = function (a,b) return map[a] == map[b] end}
  local function f(x)
    local u = T.newuserdata(0)
    debug.setmetatable(u, t)
    map[u] = x
    return u
  end
  assert(f(10) == f(10))
  assert(f(10) ~= f(11))
  assert(T.testC("equal 2 3; return 1", f(10), f(10)))
  assert(not T.testC("equal 2 3; return 1", f(10), f(20)))
  t.__eq = nil
  assert(f(10) ~= f(10))
end

print'+'



-------------------------------------------------------------------------
do   -- testing errors during GC
  local a = {}
  for i=1,20 do
    a[i] = T.newuserdata(i)   -- creates several udata
  end
  for i=1,20,2 do   -- mark half of them to raise error during GC
    debug.setmetatable(a[i], {__gc = function (x) error("error inside gc") end})
  end
  for i=2,20,2 do   -- mark the other half to count and to create more garbage
    debug.setmetatable(a[i], {__gc = function (x) loadstring("A=A+1")() end})
  end
  _G.A = 0
  a = 0
  while 1 do
  if xpcall(collectgarbage, function (s) a=a+1 end) then
    break   -- stop if no more errors
  end
  end
  assert(a == 10)  -- number of errors
  assert(A == 10)  -- number of normal collections
end
-------------------------------------------------------------------------
-- test for userdata vals
do
  local a = {}; local lim = 30
  for i=0,lim do a[i] = T.pushuserdata(i) end
  for i=0,lim do assert(T.udataval(a[i]) == i) end
  for i=0,lim do assert(T.pushuserdata(i) == a[i]) end
  for i=0,lim do a[a[i]] = i end
  for i=0,lim do a[T.pushuserdata(i)] = i end
  assert(type(tostring(a[1])) == "string")
end


-------------------------------------------------------------------------
-- testing multiple states
T.closestate(T.newstate());
L1 = T.newstate()
assert(L1)
assert(pack(T.doremote(L1, "function f () return 'alo', 3 end; f()")).n == 0)

a, b = T.doremote(L1, "return f()")
assert(a == 'alo' and b == '3')

T.doremote(L1, "_ERRORMESSAGE = nil")
-- error: `sin' is not defined
a, b = T.doremote(L1, "return sin(1)")
assert(a == nil and b == 2)   -- 2 == run-time error

-- error: syntax error
a, b, c = T.doremote(L1, "return a+")
assert(a == nil and b == 3 and type(c) == "string")   -- 3 == syntax error

T.loadlib(L1)
a, b = T.doremote(L1, [[
  a = strlibopen()
  a = packageopen()
  a = baselibopen(); assert(a == _G and require("_G") == a)
  a = iolibopen(); assert(type(a.read) == "function")
  assert(require("io") == a)
  a = tablibopen(); assert(type(a.insert) == "function")
  a = dblibopen(); assert(type(a.getlocal) == "function")
  a = mathlibopen(); assert(type(a.sin) == "function")
  return string.sub('okinama', 1, 2)
]])
assert(a == "ok")

T.closestate(L1);

L1 = T.newstate()
T.loadlib(L1)
T.doremote(L1, "a = {}")
T.testC(L1, [[pushstring a; gettable G; pushstring x; pushnum 1;
             settable -3]])
assert(T.doremote(L1, "return a.x") == "1")

T.closestate(L1)

L1 = nil

print('+')

-------------------------------------------------------------------------
-- testing memory limits
-------------------------------------------------------------------------
collectgarbage()
T.totalmem(T.totalmem()+5000)   -- set low memory limit (+5k)
assert(not pcall(loadstring"local a={}; for i=1,100000 do a[i]=i end"))
T.totalmem(1000000000)          -- restore high limit


local function stack(x) if x>0 then stack(x-1) end end

-- test memory errors; increase memory limit in small steps, so that
-- we get memory errors in different parts of a given task, up to there
-- is enough memory to complete the task without errors
function testamem (s, f)
  collectgarbage()
  stack(10)    -- ensure minimum stack size
  local M = T.totalmem()
  local oldM = M
  local a,b = nil
  while 1 do
    M = M+3   -- increase memory limit in small steps
    T.totalmem(M)
    a, b = pcall(f)
    if a and b then break end       -- stop when no more errors
    collectgarbage()
    if not a and not string.find(b, "memory") then   -- `real' error?
      T.totalmem(1000000000)  -- restore high limit
      error(b, 0)
    end
  end
  T.totalmem(1000000000)  -- restore high limit
  print("\nlimit for " .. s .. ": " .. M-oldM)
  return b
end


-- testing memory errors when creating a new state

b = testamem("state creation", T.newstate)
T.closestate(b);  -- close new state


-- testing threads

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")
loadstring(expand(20,"G=G+1"))()
assert(G==20); collectgarbage();  -- assert(gcinfo() <= a+1)

testamem("thread creation", function ()
  return T.doonnewstack("x=1") == 0  -- try to create thread
end)


-- testing memory x compiler

testamem("loadstring", function ()
  return loadstring("x=1")  -- try to do a loadstring
end)


local testprog = [[
local function foo () return end
local t = {"x"}
a = "aaa"
for _, v in ipairs(t) do a=a..v end
return true
]]

-- testing memory x dofile
_G.a = 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.a == "aaax")


-- other generic tests

testamem("string creation", 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 = loadstring(testprog)
  local b = a and string.dump(a)
  a = b and loadstring(b)
  return a and a()
end)

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)

local a = 1
close = nil
testamem("closure creation", function ()
  function close (b,c)
   return function (x) return a+b+c+x end
  end
  return (close(2,3)(4) == 10)
end)

testamem("coroutines", function ()
  local a = coroutine.wrap(function ()
              coroutine.yield(string.rep("a", 10))
              return {}
            end)
  assert(string.len(a()) == 10)
  return a()
end)

print'+'

-- testing some auxlib functions
assert(T.gsub("alo.alo.uhuh.", ".", "//") == "alo//alo//uhuh//")
assert(T.gsub("alo.alo.uhuh.", "alo", "//") == "//.//.uhuh.")
assert(T.gsub("", "alo", "//") == "")
assert(T.gsub("...", ".", "/.") == "/././.")
assert(T.gsub("...", "...", "") == "")


print'OK'


A tests/5.1.5/attrib.lua => tests/5.1.5/attrib.lua +339 -0
@@ 0,0 1,339 @@
do --[

print "testing require"

assert(require"string" == string)
assert(require"math" == math)
assert(require"table" == table)
assert(require"io" == io)
assert(require"os" == os)
assert(require"debug" == debug)
assert(require"coroutine" == coroutine)

assert(type(package.path) == "string")
assert(type(package.cpath) == "string")
assert(type(package.loaded) == "table")
assert(type(package.preload) == "table")


local DIR = "libs/"

local function createfiles (files, preextras, posextras)
  for n,c in pairs(files) do
    io.output(DIR..n)
    io.write(string.format(preextras, n))
    io.write(c)
    io.write(string.format(posextras, n))
    io.close(io.output())
  end
end

function removefiles (files)
  for n in pairs(files) do
    os.remove(DIR..n)
  end
end

local files = {
  ["A.lua"] = "",
  ["B.lua"] = "assert(...=='B');require 'A'",
  ["A.lc"] = "",
  ["A"] = "",
  ["L"] = "",
  ["XXxX"] = "",
  ["C.lua"] = "package.loaded[...] = 25; require'C'"
}

AA = nil
local extras = [[
NAME = '%s'
REQUIRED = ...
return AA]]

createfiles(files, "", extras)


local oldpath = package.path

package.path = string.gsub("D/?.lua;D/?.lc;D/?;D/??x?;D/L", "D/", DIR)

local try = function (p, n, r)
  NAME = nil
  local rr = require(p)
  assert(NAME == n)
  assert(REQUIRED == p)
  assert(rr == r)
end

assert(require"C" == 25)
assert(require"C" == 25)
AA = nil
try('B', 'B.lua', true)
assert(package.loaded.B)
assert(require"B" == true)
assert(package.loaded.A)
package.loaded.A = nil
try('B', nil, true)   -- should not reload package
try('A', 'A.lua', true)
package.loaded.A = nil
os.remove(DIR..'A.lua')
AA = {}
try('A', 'A.lc', AA)  -- now must find second option
assert(require("A") == AA)
AA = false
try('K', 'L', false)     -- default option
try('K', 'L', false)     -- default option (should reload it)
assert(rawget(_G, "_REQUIREDNAME") == nil)

AA = "x"
try("X", "XXxX", AA)


removefiles(files)


-- testing require of sub-packages

package.path = string.gsub("D/?.lua;D/?/init.lua", "D/", DIR)

files = {
  ["P1/init.lua"] = "AA = 10",
  ["P1/xuxu.lua"] = "AA = 20",
}

createfiles(files, "module(..., package.seeall)\n", "")
AA = 0

local m = assert(require"P1")
assert(m == P1 and m._NAME == "P1" and AA == 0 and m.AA == 10)
assert(require"P1" == P1 and P1 == m)
assert(require"P1" == P1)
assert(P1._PACKAGE == "")

local m = assert(require"P1.xuxu")
assert(m == P1.xuxu and m._NAME == "P1.xuxu" and AA == 0 and m.AA == 20)
assert(require"P1.xuxu" == P1.xuxu and P1.xuxu == m)
assert(require"P1.xuxu" == P1.xuxu)
assert(require"P1" == P1)
assert(P1.xuxu._PACKAGE == "P1.")
assert(P1.AA == 10 and P1._PACKAGE == "")
assert(P1._G == _G and P1.xuxu._G == _G)



removefiles(files)


package.path = ""
assert(not pcall(require, "file_does_not_exist"))
package.path = "??\0?"
assert(not pcall(require, "file_does_not_exist1"))

package.path = oldpath

-- check 'require' error message
local fname = "file_does_not_exist2"
local m, err = pcall(require, fname)
for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do
  t = string.gsub(t, "?", fname)
  assert(string.find(err, t, 1, true))
end


local function import(...)
  local f = {...}
  return function (m)
    for i=1, #f do m[f[i]] = _G[f[i]] end
  end
end

local assert, module, package = assert, module, package
X = nil; x = 0; assert(_G.x == 0)   -- `x' must be a global variable
module"X"; x = 1; assert(_M.x == 1)
module"X.a.b.c"; x = 2; assert(_M.x == 2)
module("X.a.b", package.seeall); x = 3
assert(X._NAME == "X" and X.a.b.c._NAME == "X.a.b.c" and X.a.b._NAME == "X.a.b")
assert(X._M == X and X.a.b.c._M == X.a.b.c and X.a.b._M == X.a.b)
assert(X.x == 1 and X.a.b.c.x == 2 and X.a.b.x == 3)
assert(X._PACKAGE == "" and X.a.b.c._PACKAGE == "X.a.b." and
       X.a.b._PACKAGE == "X.a.")
assert(_PACKAGE.."c" == "X.a.c")
assert(X.a._NAME == nil and X.a._M == nil)
module("X.a", import("X")) ; x = 4
assert(X.a._NAME == "X.a" and X.a.x == 4 and X.a._M == X.a)
module("X.a.b", package.seeall); assert(x == 3); x = 5
assert(_NAME == "X.a.b" and X.a.b.x == 5)

assert(X._G == nil and X.a._G == nil and X.a.b._G == _G and X.a.b.c._G == nil)

setfenv(1, _G)
assert(x == 0)

assert(not pcall(module, "x"))
assert(not pcall(module, "math.sin"))


-- testing C libraries


local p = ""   -- On Mac OS X, redefine this to "_"

-- assert(loadlib == package.loadlib)   -- only for compatibility
local f, err, when = package.loadlib("libs/lib1.so", p.."luaopen_lib1")
if not f then
  (Message or print)('\a\n >>> cannot load dynamic library <<<\n\a')
  print(err, when)
else
  f()   -- open library
  assert(require("lib1") == lib1)
  collectgarbage()
  assert(lib1.id("x") == "x")
  f = assert(package.loadlib("libs/lib1.so", p.."anotherfunc"))
  assert(f(10, 20) == "1020\n")
  f, err, when = package.loadlib("libs/lib1.so", p.."xuxu")
  assert(not f and type(err) == "string" and when == "init")
  package.cpath = "libs/?.so"
  require"lib2"
  assert(lib2.id("x") == "x")
  local fs = require"lib1.sub"
  assert(fs == lib1.sub and next(lib1.sub) == nil)
  module("lib2", package.seeall)
  f = require"-lib2"
  assert(f.id("x") == "x" and _M == f and _NAME == "lib2")
  module("lib1.sub", package.seeall)
  assert(_M == fs)
  setfenv(1, _G)
 
end
f, err, when = package.loadlib("donotexist", p.."xuxu")
assert(not f and type(err) == "string" and (when == "open" or when == "absent"))


-- testing preload

do
  local p = package
  package = {}
  p.preload.pl = function (...)
    module(...)
    function xuxu (x) return x+20 end
  end

  require"pl"
  assert(require"pl" == pl)
  assert(pl.xuxu(10) == 30)

  package = p
  assert(type(package.path) == "string")
end



end  --]

print('+')

print("testing assignments, logical operators, and constructors")

local res, res2 = 27

a, b = 1, 2+3
assert(a==1 and b==5)
a={}
function f() return 10, 11, 12 end
a.x, b, a[1] = 1, 2, f()
assert(a.x==1 and b==2 and a[1]==10)
a[f()], b, a[f()+3] = f(), a, 'x'
assert(a[10] == 10 and b == a and a[13] == 'x')

do
  local f = function (n) local x = {}; for i=1,n do x[i]=i end;
                         return unpack(x) end;
  local a,b,c
  a,b = 0, f(1)
  assert(a == 0 and b == 1)
  A,b = 0, f(1)
  assert(A == 0 and b == 1)
  a,b,c = 0,5,f(4)
  assert(a==0 and b==5 and c==1)
  a,b,c = 0,5,f(0)
  assert(a==0 and b==5 and c==nil)
end


a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
assert(not a and b and c and d==6)

d = 20
a, b, c, d = f()
assert(a==10 and b==11 and c==12 and d==nil)
a,b = f(), 1, 2, 3, f()
assert(a==10 and b==1)

assert(a<b == false and a>b == true)
assert((10 and 2) == 2)
assert((10 or 2) == 10)
assert((10 or assert(nil)) == 10)
assert(not (nil and assert(nil)))
assert((nil or "alo") == "alo")
assert((nil and 10) == nil)
assert((false and 10) == false)
assert((true or 10) == true)
assert((false or 10) == 10)
assert(false ~= nil)
assert(nil ~= false)
assert(not nil == true)
assert(not not nil == false)
assert(not not 1 == true)
assert(not not a == true)
assert(not not (6 or nil) == true)
assert(not not (nil and 56) == false)
assert(not not (nil and true) == false)
print('+')

a = {}
a[true] = 20
a[false] = 10
assert(a[1<2] == 20 and a[1>2] == 10)

function f(a) return a end

local a = {}
for i=3000,-3000,-1 do a[i] = i; end
a[10e30] = "alo"; a[true] = 10; a[false] = 20
assert(a[10e30] == 'alo' and a[not 1] == 20 and a[10<20] == 10)
for i=3000,-3000,-1 do assert(a[i] == i); end
a[print] = assert
a[f] = print
a[a] = a
assert(a[a][a][a][a][print] == assert)
a[print](a[a[f]] == a[print])
a = nil

a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'}
a, a.x, a.y = a, a[-3]
assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
a[1], f(a)[2], b, c = {['alo']=assert}, 10, a[1], a[f], 6, 10, 23, f(a), 2
a[1].alo(a[2]==10 and b==10 and c==print)

a[2^31] = 10; a[2^31+1] = 11; a[-2^31] = 12;
a[2^32] = 13; a[-2^32] = 14; a[2^32+1] = 15; a[10^33] = 16;

assert(a[2^31] == 10 and a[2^31+1] == 11 and a[-2^31] == 12 and
       a[2^32] == 13 and a[-2^32] == 14 and a[2^32+1] == 15 and
       a[10^33] == 16)

a = nil


do
  local a,i,j,b
  a = {'a', 'b'}; i=1; j=2; b=a
  i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i
  assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and
         b[3] == 1)
end

print('OK')

return res

A tests/5.1.5/basic.bat => tests/5.1.5/basic.bat +5 -0
@@ 0,0 1,5 @@
@echo off

echo Using %LUA%

call ..\..\%LUA% -e"_U=true" all.lua
\ No newline at end of file

A tests/5.1.5/big.lua => tests/5.1.5/big.lua +381 -0
@@ 0,0 1,381 @@
print "testing string length overflow"

local longs = string.rep("\0", 2^25)
local function catter (i)
  return assert(loadstring(
    string.format("return function(a) return a%s end",
                     string.rep("..a", i-1))))()
end
rep129 = catter(129)
local a, b = pcall(rep129, longs)
assert(not a and string.find(b, "overflow"))
print('+')


require "checktable"

--[[ lots of empty lines (to force SETLINEW)











































































































































































































--]]


a,b = nil,nil
while not b do
if a then
b = {  -- lots of strings (to force JMPW and PUSHCONSTANTW)
"n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9", "n10",
"n11", "n12", "j301", "j302", "j303", "j304", "j305", "j306", "j307", "j308",
"j309", "a310", "n311", "n312", "n313", "n314", "n315", "n316", "n317", "n318",
"n319", "n320", "n321", "n322", "n323", "n324", "n325", "n326", "n327", "n328",
"a329", "n330", "n331", "n332", "n333", "n334", "n335", "n336", "n337", "n338",
"n339", "n340", "n341", "z342", "n343", "n344", "n345", "n346", "n347", "n348",
"n349", "n350", "n351", "n352", "r353", "n354", "n355", "n356", "n357", "n358",
"n359", "n360", "n361", "n362", "n363", "n364", "n365", "n366", "z367", "n368",
"n369", "n370", "n371", "n372", "n373", "n374", "n375", "a376", "n377", "n378",
"n379", "n380", "n381", "n382", "n383", "n384", "n385", "n386", "n387", "n388",
"n389", "n390", "n391", "n392", "n393", "n394", "n395", "n396", "n397", "n398",
"n399", "n400", "n13", "n14", "n15", "n16", "n17", "n18", "n19", "n20",
"n21", "n22", "n23", "a24", "n25", "n26", "n27", "n28", "n29", "j30",
"n31", "n32", "n33", "n34", "n35", "n36", "n37", "n38", "n39", "n40",
"n41", "n42", "n43", "n44", "n45", "n46", "n47", "n48", "n49", "n50",
"n51", "n52", "n53", "n54", "n55", "n56", "n57", "n58", "n59", "n60",
"n61", "n62", "n63", "n64", "n65", "a66", "z67", "n68", "n69", "n70",
"n71", "n72", "n73", "n74", "n75", "n76", "n77", "n78", "n79", "n80",
"n81", "n82", "n83", "n84", "n85", "n86", "n87", "n88", "n89", "n90",
"n91", "n92", "n93", "n94", "n95", "n96", "n97", "n98", "n99", "n100",
"n201", "n202", "n203", "n204", "n205", "n206", "n207", "n208", "n209", "n210",
"n211", "n212", "n213", "n214", "n215", "n216", "n217", "n218", "n219", "n220",
"n221", "n222", "n223", "n224", "n225", "n226", "n227", "n228", "n229", "n230",
"n231", "n232", "n233", "n234", "n235", "n236", "n237", "n238", "n239", "a240",
"a241", "a242", "a243", "a244", "a245", "a246", "a247", "a248", "a249", "n250",
"n251", "n252", "n253", "n254", "n255", "n256", "n257", "n258", "n259", "n260",
"n261", "n262", "n263", "n264", "n265", "n266", "n267", "n268", "n269", "n270",
"n271", "n272", "n273", "n274", "n275", "n276", "n277", "n278", "n279", "n280",
"n281", "n282", "n283", "n284", "n285", "n286", "n287", "n288", "n289", "n290",
"n291", "n292", "n293", "n294", "n295", "n296", "n297", "n298", "n299"
; x=23}
else a = 1 end


end

assert(b.x == 23)
print('+')

stat(b)

repeat
a = {
n1 = 1.5, n2 = 2.5, n3 = 3.5, n4 = 4.5, n5 = 5.5, n6 = 6.5, n7 = 7.5,
n8 = 8.5, n9 = 9.5, n10 = 10.5, n11 = 11.5, n12 = 12.5,
j301 = 301.5, j302 = 302.5, j303 = 303.5, j304 = 304.5, j305 = 305.5,
j306 = 306.5, j307 = 307.5, j308 = 308.5, j309 = 309.5, a310 = 310.5,
n311 = 311.5, n312 = 312.5, n313 = 313.5, n314 = 314.5, n315 = 315.5,
n316 = 316.5, n317 = 317.5, n318 = 318.5, n319 = 319.5, n320 = 320.5,
n321 = 321.5, n322 = 322.5, n323 = 323.5, n324 = 324.5, n325 = 325.5,
n326 = 326.5, n327 = 327.5, n328 = 328.5, a329 = 329.5, n330 = 330.5,
n331 = 331.5, n332 = 332.5, n333 = 333.5, n334 = 334.5, n335 = 335.5,
n336 = 336.5, n337 = 337.5, n338 = 338.5, n339 = 339.5, n340 = 340.5,
n341 = 341.5, z342 = 342.5, n343 = 343.5, n344 = 344.5, n345 = 345.5,
n346 = 346.5, n347 = 347.5, n348 = 348.5, n349 = 349.5, n350 = 350.5,
n351 = 351.5, n352 = 352.5, r353 = 353.5, n354 = 354.5, n355 = 355.5,
n356 = 356.5, n357 = 357.5, n358 = 358.5, n359 = 359.5, n360 = 360.5,
n361 = 361.5, n362 = 362.5, n363 = 363.5, n364 = 364.5, n365 = 365.5,
n366 = 366.5, z367 = 367.5, n368 = 368.5, n369 = 369.5, n370 = 370.5,
n371 = 371.5, n372 = 372.5, n373 = 373.5, n374 = 374.5, n375 = 375.5,
a376 = 376.5, n377 = 377.5, n378 = 378.5, n379 = 379.5, n380 = 380.5,
n381 = 381.5, n382 = 382.5, n383 = 383.5, n384 = 384.5, n385 = 385.5,
n386 = 386.5, n387 = 387.5, n388 = 388.5, n389 = 389.5, n390 = 390.5,
n391 = 391.5, n392 = 392.5, n393 = 393.5, n394 = 394.5, n395 = 395.5,
n396 = 396.5, n397 = 397.5, n398 = 398.5, n399 = 399.5, n400 = 400.5,
n13 = 13.5, n14 = 14.5, n15 = 15.5, n16 = 16.5, n17 = 17.5,
n18 = 18.5, n19 = 19.5, n20 = 20.5, n21 = 21.5, n22 = 22.5,
n23 = 23.5, a24 = 24.5, n25 = 25.5, n26 = 26.5, n27 = 27.5,
n28 = 28.5, n29 = 29.5, j30 = 30.5, n31 = 31.5, n32 = 32.5,
n33 = 33.5, n34 = 34.5, n35 = 35.5, n36 = 36.5, n37 = 37.5,
n38 = 38.5, n39 = 39.5, n40 = 40.5, n41 = 41.5, n42 = 42.5,
n43 = 43.5, n44 = 44.5, n45 = 45.5, n46 = 46.5, n47 = 47.5,
n48 = 48.5, n49 = 49.5, n50 = 50.5, n51 = 51.5, n52 = 52.5,
n53 = 53.5, n54 = 54.5, n55 = 55.5, n56 = 56.5, n57 = 57.5,
n58 = 58.5, n59 = 59.5, n60 = 60.5, n61 = 61.5, n62 = 62.5,
n63 = 63.5, n64 = 64.5, n65 = 65.5, a66 = 66.5, z67 = 67.5,
n68 = 68.5, n69 = 69.5, n70 = 70.5, n71 = 71.5, n72 = 72.5,
n73 = 73.5, n74 = 74.5, n75 = 75.5, n76 = 76.5, n77 = 77.5,
n78 = 78.5, n79 = 79.5, n80 = 80.5, n81 = 81.5, n82 = 82.5,
n83 = 83.5, n84 = 84.5, n85 = 85.5, n86 = 86.5, n87 = 87.5,
n88 = 88.5, n89 = 89.5, n90 = 90.5, n91 = 91.5, n92 = 92.5,
n93 = 93.5, n94 = 94.5, n95 = 95.5, n96 = 96.5, n97 = 97.5,
n98 = 98.5, n99 = 99.5, n100 = 100.5, n201 = 201.5, n202 = 202.5,
n203 = 203.5, n204 = 204.5, n205 = 205.5, n206 = 206.5, n207 = 207.5,
n208 = 208.5, n209 = 209.5, n210 = 210.5, n211 = 211.5, n212 = 212.5,
n213 = 213.5, n214 = 214.5, n215 = 215.5, n216 = 216.5, n217 = 217.5,
n218 = 218.5, n219 = 219.5, n220 = 220.5, n221 = 221.5, n222 = 222.5,
n223 = 223.5, n224 = 224.5, n225 = 225.5, n226 = 226.5, n227 = 227.5,
n228 = 228.5, n229 = 229.5, n230 = 230.5, n231 = 231.5, n232 = 232.5,
n233 = 233.5, n234 = 234.5, n235 = 235.5, n236 = 236.5, n237 = 237.5,
n238 = 238.5, n239 = 239.5, a240 = 240.5, a241 = 241.5, a242 = 242.5,
a243 = 243.5, a244 = 244.5, a245 = 245.5, a246 = 246.5, a247 = 247.5,
a248 = 248.5, a249 = 249.5, n250 = 250.5, n251 = 251.5, n252 = 252.5,
n253 = 253.5, n254 = 254.5, n255 = 255.5, n256 = 256.5, n257 = 257.5,
n258 = 258.5, n259 = 259.5, n260 = 260.5, n261 = 261.5, n262 = 262.5,
n263 = 263.5, n264 = 264.5, n265 = 265.5, n266 = 266.5, n267 = 267.5,
n268 = 268.5, n269 = 269.5, n270 = 270.5, n271 = 271.5, n272 = 272.5,
n273 = 273.5, n274 = 274.5, n275 = 275.5, n276 = 276.5, n277 = 277.5,
n278 = 278.5, n279 = 279.5, n280 = 280.5, n281 = 281.5, n282 = 282.5,
n283 = 283.5, n284 = 284.5, n285 = 285.5, n286 = 286.5, n287 = 287.5,
n288 = 288.5, n289 = 289.5, n290 = 290.5, n291 = 291.5, n292 = 292.5,
n293 = 293.5, n294 = 294.5, n295 = 295.5, n296 = 296.5, n297 = 297.5,
n298 = 298.5, n299 = 299.5, j300 = 300} or 1
until 1

assert(a.n299 == 299.5)
xxx = 1
assert(xxx == 1)

stat(a)

function a:findfield (f)
  local i,v = next(self, nil)
  while i ~= f do
    if not i then return end
    i,v = next(self, i)
  end
  return v
end

local ii = 0
i = 1
while b[i] do
  local r = a:findfield(b[i]);
  assert(a[b[i]] == r)
  ii = math.max(ii,i)
  i = i+1
end

assert(ii == 299)

function xxxx (x) coroutine.yield('b'); return ii+x end

assert(xxxx(10) == 309)

a = nil
b = nil
a1 = nil

print("tables with table indices:")
i = 1; a={}
while i <= 1023 do a[{}] = i; i=i+1 end
stat(a)
a = nil

print("tables with function indices:")
a={}
for i=1,511 do local x; a[function () return x end] = i end
stat(a)
a = nil

print'OK'

return 'a'

A tests/5.1.5/calls.lua => tests/5.1.5/calls.lua +294 -0
@@ 0,0 1,294 @@
print("testing functions and calls")

-- get the opportunity to test 'type' too ;)

assert(type(1<2) == 'boolean')
assert(type(true) == 'boolean' and type(false) == 'boolean')
assert(type(nil) == 'nil' and type(-3) == 'number' and type'x' == 'string' and
       type{} == 'table' and type(type) == 'function')

assert(type(assert) == type(print))
f = nil
function f (x) return a:x (x) end
assert(type(f) == 'function')


-- testing local-function recursion
fact = false
do
  local res = 1
  local function fact (n)
    if n==0 then return res
    else return n*fact(n-1)
    end
  end
  assert(fact(5) == 120)
end
assert(fact == false)

-- testing declarations
a = {i = 10}
self = 20
function a:x (x) return x+self.i end
function a.y (x) return x+self end

assert(a:x(1)+10 == a.y(1))

a.t = {i=-100}
a["t"].x = function (self, a,b) return self.i+a+b end

assert(a.t:x(2,3) == -95)

do
  local a = {x=0}
  function a:add (x) self.x, a.y = self.x+x, 20; return self end
  assert(a:add(10):add(20):add(30).x == 60 and a.y == 20)
end

local a = {b={c={}}}

function a.b.c.f1 (x) return x+1 end
function a.b.c:f2 (x,y) self[x] = y end
assert(a.b.c.f1(4) == 5)
a.b.c:f2('k', 12); assert(a.b.c.k == 12)

print('+')

t = nil   -- 'declare' t
function f(a,b,c) local d = 'a'; t={a,b,c,d} end

f(      -- this line change must be valid
  1,2)
assert(t[1] == 1 and t[2] == 2 and t[3] == nil and t[4] == 'a')
f(1,2,   -- this one too
      3,4)
assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a')

function fat(x)
  if x <= 1 then return 1
  else return x*loadstring("return fat(" .. x-1 .. ")")()
  end
end

assert(loadstring "loadstring 'assert(fat(6)==720)' () ")()
a = loadstring('return fat(5), 3')
a,b = a()
assert(a == 120 and b == 3)
print('+')

function err_on_n (n)
  if n==0 then error(); exit(1);
  else err_on_n (n-1); exit(1);
  end
end

do
  function dummy (n)
    if n > 0 then
      assert(not pcall(err_on_n, n))
      dummy(n-1)
    end
  end
end

dummy(10)

function deep (n)
  if n>0 then deep(n-1) end
end
deep(10)
deep(200)

-- testing tail call
function deep (n) if n>0 then return deep(n-1) else return 101 end end
assert(deep(30000) == 101)
a = {}
function a:deep (n) if n>0 then return self:deep(n-1) else return 101 end end
assert(a:deep(30000) == 101)

print('+')


a = nil
(function (x) a=x end)(23)
assert(a == 23 and (function (x) return x*2 end)(20) == 40)


local x,y,z,a
a = {}; lim = 2000
for i=1, lim do a[i]=i end
assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
x = unpack(a)
assert(x == 1)
x = {unpack(a)}
assert(table.getn(x) == lim and x[1] == 1 and x[lim] == lim)
x = {unpack(a, lim-2)}
assert(table.getn(x) == 3 and x[1] == lim-2 and x[3] == lim)
x = {unpack(a, 10, 6)}
assert(next(x) == nil)   -- no elements
x = {unpack(a, 11, 10)}
assert(next(x) == nil)   -- no elements
x,y = unpack(a, 10, 10)
assert(x == 10 and y == nil)
x,y,z = unpack(a, 10, 11)
assert(x == 10 and y == 11 and z == nil)
a,x = unpack{1}
assert(a==1 and x==nil)
a,x = unpack({1,2}, 1, 1)
assert(a==1 and x==nil)


-- testing closures

-- fixed-point operator
Y = function (le)
      local function a (f)
        return le(function (x) return f(f)(x) end)
      end
      return a(a)
    end


-- non-recursive factorial

F = function (f)
      return function (n)
               if n == 0 then return 1
               else return n*f(n-1) end
             end
    end

fat = Y(F)

assert(fat(0) == 1 and fat(4) == 24 and Y(F)(5)==5*Y(F)(4))

local function g (z)
  local function f (a,b,c,d)
    return function (x,y) return a+b+c+d+a+x+y+z end
  end
  return f(z,z+1,z+2,z+3)
end

f = g(10)
assert(f(9, 16) == 10+11+12+13+10+9+16+10)

Y, F, f = nil
print('+')

-- testing multiple returns

function unlpack (t, i)
  i = i or 1
  if (i <= table.getn(t)) then
    return t[i], unlpack(t, i+1)
  end
end

function equaltab (t1, t2)
  assert(table.getn(t1) == table.getn(t2))
  for i,v1 in ipairs(t1) do
    assert(v1 == t2[i])
  end
end

local function pack (...)
  local x = {...}
  x.n = select('#', ...)
  return x
end

function f() return 1,2,30,4 end
function ret2 (a,b) return a,b end

local a,b,c,d = unlpack{1,2,3}
assert(a==1 and b==2 and c==3 and d==nil)
a = {1,2,3,4,false,10,'alo',false,assert}
equaltab(pack(unlpack(a)), a)
equaltab(pack(unlpack(a), -1), {1,-1})
a,b,c,d = ret2(f()), ret2(f())
assert(a==1 and b==1 and c==2 and d==nil)
a,b,c,d = unlpack(pack(ret2(f()), ret2(f())))
assert(a==1 and b==1 and c==2 and d==nil)
a,b,c,d = unlpack(pack(ret2(f()), (ret2(f()))))
assert(a==1 and b==1 and c==nil and d==nil)

a = ret2{ unlpack{1,2,3}, unlpack{3,2,1}, unlpack{"a", "b"}}
assert(a[1] == 1 and a[2] == 3 and a[3] == "a" and a[4] == "b")


-- testing calls with 'incorrect' arguments
rawget({}, "x", 1)
rawset({}, "x", 1, 2)
assert(math.sin(1,2) == math.sin(1))
table.sort({10,9,8,4,19,23,0,0}, function (a,b) return a<b end, "extra arg")


-- test for generic load
x = "-- a comment\0\0\0\n  x = 10 + \n23; \
     local a = function () x = 'hi' end; \
     return '\0'"
local i = 0
function read1 (x)
  return function ()
    collectgarbage()
    i=i+1
    return string.sub(x, i, i)
  end
end

a = assert(load(read1(x), "modname"))
assert(a() == "\0" and _G.x == 33)
assert(debug.getinfo(a).source == "modname")

x = string.dump(loadstring("x = 1; return x"))
i = 0
a = assert(load(read1(x)))
assert(a() == 1 and _G.x == 1)

i = 0
local a, b = load(read1("*a = 123"))
assert(not a and type(b) == "string" and i == 2)

a, b = load(function () error("hhi") end)
assert(not a and string.find(b, "hhi"))

-- test generic load with nested functions
x = [[
  return function (x)
    return function (y)
     return function (z)
       return x+y+z
     end
   end
  end
]]

a = assert(load(read1(x)))
assert(a()(2)(3)(10) == 15)


-- test for dump/undump with upvalues
local a, b = 20, 30
x = loadstring(string.dump(function (x)
  if x == "set" then a = 10+b; b = b+1 else
  return a
  end
end))
assert(x() == nil)
assert(debug.setupvalue(x, 1, "hi") == "a")
assert(x() == "hi")
assert(debug.setupvalue(x, 2, 13) == "b")
assert(not debug.setupvalue(x, 3, 10))   -- only 2 upvalues
x("set")
assert(x() == 23)
x("set")
assert(x() == 24)


-- test for bug in parameter adjustment
assert((function () return nil end)(4) == nil)
assert((function () local a; return a end)(4) == nil)
assert((function (a) return a end)() == nil)

print('OK')
return deep

A tests/5.1.5/checktable.lua => tests/5.1.5/checktable.lua +77 -0
@@ 0,0 1,77 @@

assert(rawget(_G, "stat") == nil)  -- module not loaded before

if T == nil then
  stat = function () print"`querytab' nao ativo" end
  return
end


function checktable (t)
  local asize, hsize, ff = T.querytab(t)
  local l = {}
  for i=0,hsize-1 do
    local key,val,next = T.querytab(t, i + asize)
    if key == nil then
      assert(l[i] == nil and val==nil and next==nil)
    elseif key == "<undef>" then
      assert(val==nil)
    else
      assert(t[key] == val)
      local mp = T.hash(key, t)
      if l[i] then
        assert(l[i] == mp)
      elseif mp ~= i then
        l[i] = mp
      else  -- list head
        l[mp] = {mp}   -- first element
        while next do
          assert(ff <= next and next < hsize)
          if l[next] then assert(l[next] == mp) else l[next] = mp end
          table.insert(l[mp], next)
          key,val,next = T.querytab(t, next)
          assert(key)
        end
      end
    end
  end
  l.asize = asize; l.hsize = hsize; l.ff = ff
  return l
end

function mostra (t)
  local asize, hsize, ff = T.querytab(t)
  print(asize, hsize, ff)
  print'------'
  for i=0,asize-1 do
    local _, v = T.querytab(t, i)
    print(string.format("[%d] -", i), v)
  end
  print'------'
  for i=0,hsize-1 do
    print(i, T.querytab(t, i+asize))
  end
  print'-------------'
end

function stat (t)
  t = checktable(t)
  local nelem, nlist = 0, 0
  local maxlist = {}
  for i=0,t.hsize-1 do
    if type(t[i]) == 'table' then
      local n = table.getn(t[i])
      nlist = nlist+1
      nelem = nelem + n
      if not maxlist[n] then maxlist[n] = 0 end
      maxlist[n] = maxlist[n]+1
    end
  end
  print(string.format("hsize=%d  elements=%d  load=%.2f  med.len=%.2f (asize=%d)",
          t.hsize, nelem, nelem/t.hsize, nelem/nlist, t.asize))
  for i=1,table.getn(maxlist) do
    local n = maxlist[i] or 0
    print(string.format("%5d %10d %.2f%%", i, n, n*100/nlist))
  end
end


A tests/5.1.5/closure.lua => tests/5.1.5/closure.lua +422 -0
@@ 0,0 1,422 @@
print "testing closures and coroutines"

local A,B = 0,{g=10}
function f(x)
  local a = {}
  for i=1,1000 do
    local y = 0
    do
      a[i] = function () B.g = B.g+1; y = y+x; return y+A end
    end
  end
  local dummy = function () return a[A] end
  collectgarbage()
  A = 1; assert(dummy() == a[1]); A = 0;
  assert(a[1]() == x)
  assert(a[3]() == x)
  collectgarbage()
  assert(B.g == 12)
  return a
end

a = f(10)
-- force a GC in this level
local x = {[1] = {}}   -- to detect a GC
setmetatable(x, {__mode = 'kv'})
while x[1] do   -- repeat until GC
  local a = A..A..A..A  -- create garbage
  A = A+1
end
assert(a[1]() == 20+A)
assert(a[1]() == 30+A)
assert(a[2]() == 10+A)
collectgarbage()
assert(a[2]() == 20+A)
assert(a[2]() == 30+A)
assert(a[3]() == 20+A)
assert(a[8]() == 10+A)
assert(getmetatable(x).__mode == 'kv')
assert(B.g == 19)

-- testing closures with 'for' control variable
a = {}
for i=1,10 do
  a[i] = {set = function(x) i=x end, get = function () return i end}
  if i == 3 then break end
end
assert(a[4] == nil)
a[1].set(10)
assert(a[2].get() == 2)
a[2].set('a')
assert(a[3].get() == 3)
assert(a[2].get() == 'a')

a = {}
for i, k in pairs{'a', 'b'} do
  a[i] = {set = function(x, y) i=x; k=y end,
          get = function () return i, k end}
  if i == 2 then break end
end
a[1].set(10, 20)
local r,s = a[2].get()
assert(r == 2 and s == 'b')
r,s = a[1].get()
assert(r == 10 and s == 20)
a[2].set('a', 'b')
r,s = a[2].get()
assert(r == "a" and s == "b")


-- testing closures with 'for' control variable x break
for i=1,3 do
  f = function () return i end
  break
end
assert(f() == 1)

for k, v in pairs{"a", "b"} do
  f = function () return k, v end
  break
end
assert(({f()})[1] == 1)
assert(({f()})[2] == "a")


-- testing closure x break x return x errors

local b
function f(x)
  local first = 1
  while 1 do
    if x == 3 and not first then return end
    local a = 'xuxu'
    b = function (op, y)
          if op == 'set' then
            a = x+y
          else
            return a
          end
        end
    if x == 1 then do break end
    elseif x == 2 then return
    else if x ~= 3 then error() end
    end
    first = nil
  end
end

for i=1,3 do
  f(i)
  assert(b('get') == 'xuxu')
  b('set', 10); assert(b('get') == 10+i)
  b = nil
end

pcall(f, 4);
assert(b('get') == 'xuxu')
b('set', 10); assert(b('get') == 14)


local w
-- testing multi-level closure
function f(x)
  return function (y)
    return function (z) return w+x+y+z end
  end
end

y = f(10)
w = 1.345
assert(y(20)(30) == 60+w)

-- testing closures x repeat-until

local a = {}
local i = 1
repeat
  local x = i
  a[i] = function () i = x+1; return x end
until i > 10 or a[i]() ~= x
assert(i == 11 and a[1]() == 1 and a[3]() == 3 and i == 4)

print'+'


-- test for correctly closing upvalues in tail calls of vararg functions
local function t ()
  local function c(a,b) assert(a=="test" and b=="OK") end
  local function v(f, ...) c("test", f() ~= 1 and "FAILED" or "OK") end
  local x = 1
  return v(function() return x end)
end
t()


-- coroutine tests

local f

assert(coroutine.running() == nil)


-- tests for global environment

local function foo (a)
  setfenv(0, a)
  coroutine.yield(getfenv())
  assert(getfenv(0) == a)
  assert(getfenv(1) == _G)
  assert(getfenv(loadstring"") == a)
  return getfenv()
end

f = coroutine.wrap(foo)
local a = {}
assert(f(a) == _G)
local a,b = pcall(f)
assert(a and b == _G)


-- tests for multiple yield/resume arguments

local function eqtab (t1, t2)
  assert(table.getn(t1) == table.getn(t2))
  for i,v in ipairs(t1) do
    assert(t2[i] == v)
  end
end

_G.x = nil   -- declare x
function foo (a, ...)
  assert(coroutine.running() == f)
  assert(coroutine.status(f) == "running")
  local arg = {...}
  for i=1,table.getn(arg) do
    _G.x = {coroutine.yield(unpack(arg[i]))}
  end
  return unpack(a)
end

f = coroutine.create(foo)
assert(type(f) == "thread" and coroutine.status(f) == "suspended")
assert(string.find(tostring(f), "thread"))
local s,a,b,c,d
s,a,b,c,d = coroutine.resume(f, {1,2,3}, {}, {1}, {'a', 'b', 'c'})
assert(s and a == nil and coroutine.status(f) == "suspended")
s,a,b,c,d = coroutine.resume(f)
eqtab(_G.x, {})
assert(s and a == 1 and b == nil)
s,a,b,c,d = coroutine.resume(f, 1, 2, 3)
eqtab(_G.x, {1, 2, 3})
assert(s and a == 'a' and b == 'b' and c == 'c' and d == nil)
s,a,b,c,d = coroutine.resume(f, "xuxu")
eqtab(_G.x, {"xuxu"})
assert(s and a == 1 and b == 2 and c == 3 and d == nil)
assert(coroutine.status(f) == "dead")
s, a = coroutine.resume(f, "xuxu")
assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")


-- yields in tail calls
local function foo (i) return coroutine.yield(i) end
f = coroutine.wrap(function ()
  for i=1,10 do
    assert(foo(i) == _G.x)
  end
  return 'a'
end)
for i=1,10 do _G.x = i; assert(f(i) == i) end
_G.x = 'xuxu'; assert(f('xuxu') == 'a')

-- recursive
function pf (n, i)
  coroutine.yield(n)
  pf(n*i, i+1)
end

f = coroutine.wrap(pf)
local s=1
for i=1,10 do
  assert(f(1, 1) == s)
  s = s*i
end

-- sieve
function gen (n)
  return coroutine.wrap(function ()
    for i=2,n do coroutine.yield(i) end
  end)
end


function filter (p, g)
  return coroutine.wrap(function ()
    while 1 do
      local n = g()
      if n == nil then return end
      if math.mod(n, p) ~= 0 then coroutine.yield(n) end
    end
  end)
end

local x = gen(100)
local a = {}
while 1 do
  local n = x()
  if n == nil then break end
  table.insert(a, n)
  x = filter(n, x)
end

assert(table.getn(a) == 25 and a[table.getn(a)] == 97)


-- errors in coroutines
function foo ()
  assert(debug.getinfo(1).currentline == debug.getinfo(foo).linedefined + 1)
  assert(debug.getinfo(2).currentline == debug.getinfo(goo).linedefined)
  coroutine.yield(3)
  error(foo)
end

function goo() foo() end
x = coroutine.wrap(goo)
assert(x() == 3)
local a,b = pcall(x)
assert(not a and b == foo)

x = coroutine.create(goo)
a,b = coroutine.resume(x)
assert(a and b == 3)
a,b = coroutine.resume(x)
assert(not a and b == foo and coroutine.status(x) == "dead")
a,b = coroutine.resume(x)
assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")


-- co-routines x for loop
function all (a, n, k)
  if k == 0 then coroutine.yield(a)
  else
    for i=1,n do
      a[k] = i
      all(a, n, k-1)
    end
  end
end

local a = 0
for t in coroutine.wrap(function () all({}, 5, 4) end) do
  a = a+1
end
assert(a == 5^4)


-- access to locals of collected corroutines
local C = {}; setmetatable(C, {__mode = "kv"})
local x = coroutine.wrap (function ()
            local a = 10
            local function f () a = a+10; return a end
            while true do
              a = a+1
              coroutine.yield(f)
            end
          end)

C[1] = x;

local f = x()
assert(f() == 21 and x()() == 32 and x() == f)
x = nil
collectgarbage()
assert(C[1] == nil)
assert(f() == 43 and f() == 53)


-- old bug: attempt to resume itself

function co_func (current_co)
  assert(coroutine.running() == current_co)
  assert(coroutine.resume(current_co) == false)
  assert(coroutine.resume(current_co) == false)
  return 10
end

local co = coroutine.create(co_func)
local a,b = coroutine.resume(co, co)
assert(a == true and b == 10)
assert(coroutine.resume(co, co) == false)
assert(coroutine.resume(co, co) == false)

-- access to locals of erroneous coroutines
local x = coroutine.create (function ()
            local a = 10
            _G.f = function () a=a+1; return a end
            error('x')
          end)

assert(not coroutine.resume(x))
-- overwrite previous position of local `a'
assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
assert(_G.f() == 11)
assert(_G.f() == 12)


if not T then
  (Message or print)('\a\n >>> testC not active: skipping yield/hook tests <<<\n\a')
else

  local turn
  
  function fact (t, x)
    assert(turn == t)
    if x == 0 then return 1
    else return x*fact(t, x-1)
    end
  end

  local A,B,a,b = 0,0,0,0

  local x = coroutine.create(function ()
    T.setyhook("", 2)
    A = fact("A", 10)
  end)

  local y = coroutine.create(function ()
    T.setyhook("", 3)
    B = fact("B", 11)
  end)

  while A==0 or B==0 do
    if A==0 then turn = "A"; T.resume(x) end
    if B==0 then turn = "B"; T.resume(y) end
  end

  assert(B/A == 11)
end


-- leaving a pending coroutine open
_X = coroutine.wrap(function ()
      local a = 10
      local x = function () a = a+1 end
      coroutine.yield()
    end)

_X()


-- coroutine environments
co = coroutine.create(function ()
       coroutine.yield(getfenv(0))
       return loadstring("return a")()
     end)

a = {a = 15}
debug.setfenv(co, a)
assert(debug.getfenv(co) == a)
assert(select(2, coroutine.resume(co)) == a)
assert(select(2, coroutine.resume(co)) == a.a)


print'OK'

A tests/5.1.5/code.lua => tests/5.1.5/code.lua +143 -0
@@ 0,0 1,143 @@

if T==nil then
  (Message or print)('\a\n >>> testC not active: skipping opcode tests <<<\n\a')
  return
end
print "testing code generation and optimizations"


-- this code gave an error for the code checker
do
  local function f (a)
  for k,v,w in a do end
  end
end


function check (f, ...)
  local c = T.listcode(f)
  for i=1, arg.n do
    -- print(arg[i], c[i])
    assert(string.find(c[i], '- '..arg[i]..' *%d'))
  end
  assert(c[arg.n+2] == nil)
end


function checkequal (a, b)
  a = T.listcode(a)
  b = T.listcode(b)
  for i = 1, table.getn(a) do
    a[i] = string.gsub(a[i], '%b()', '')   -- remove line number
    b[i] = string.gsub(b[i], '%b()', '')   -- remove line number
    assert(a[i] == b[i])
  end
end


-- some basic instructions
check(function ()
  (function () end){f()}
end, 'CLOSURE', 'NEWTABLE', 'GETGLOBAL', 'CALL', 'SETLIST', 'CALL', 'RETURN')


-- sequence of LOADNILs
check(function ()
  local a,b,c
  local d; local e;
  a = nil; d=nil
end, 'RETURN')


-- single return
check (function (a,b,c) return a end, 'RETURN')


-- infinite loops
check(function () while true do local a = -1 end end,
'LOADK', 'JMP', 'RETURN')

check(function () while 1 do local a = -1 end end,
'LOADK', 'JMP', 'RETURN')

check(function () repeat local x = 1 until false end,
'LOADK', 'JMP', 'RETURN')

check(function () repeat local x until nil end,
'LOADNIL', 'JMP', 'RETURN')

check(function () repeat local x = 1 until true end,
'LOADK', 'RETURN')


-- concat optimization
check(function (a,b,c,d) return a..b..c..d end,
  'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN')

-- not
check(function () return not not nil end, 'LOADBOOL', 'RETURN')
check(function () return not not false end, 'LOADBOOL', 'RETURN')
check(function () return not not true end, 'LOADBOOL', 'RETURN')
check(function () return not not 1 end, 'LOADBOOL', 'RETURN')

-- direct access to locals
check(function ()
  local a,b,c,d
  a = b*2
  c[4], a[b] = -((a + d/-20.5 - a[b]) ^ a.x), b
end,
  'MUL',
  'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE', 'POW',
    'UNM', 'SETTABLE', 'SETTABLE', 'RETURN')


-- direct access to constants
check(function ()
  local a,b
  a.x = 0
  a.x = b
  a[b] = 'y'
  a = 1 - a
  b = 1/a
  b = 5+4
  a[true] = false
end,
  'SETTABLE', 'SETTABLE', 'SETTABLE', 'SUB', 'DIV', 'LOADK',
  'SETTABLE', 'RETURN')

local function f () return -((2^8 + -(-1)) % 8)/2 * 4 - 3 end

check(f, 'LOADK', 'RETURN')
assert(f() == -5)

check(function ()
  local a,b,c
  b[c], a = c, b
  b[a], a = c, b
  a, b = c, a
  a = a
end, 
  'MOVE', 'MOVE', 'SETTABLE',
  'MOVE', 'MOVE', 'MOVE', 'SETTABLE',
  'MOVE', 'MOVE', 'MOVE',
  -- no code for a = a
  'RETURN')


-- x == nil , x ~= nil
checkequal(function () if (a==nil) then a=1 end; if a~=nil then a=1 end end,
           function () if (a==9) then a=1 end; if a~=9 then a=1 end end)

check(function () if a==nil then a=1 end end,
'GETGLOBAL', 'EQ', 'JMP', 'LOADK', 'SETGLOBAL', 'RETURN')

-- de morgan
checkequal(function () local a; if not (a or b) then b=a end end,
           function () local a; if (not a and not b) then b=a end end)

checkequal(function (l) local a; return 0 <= a and a <= l end,
           function (l) local a; return not (not(a >= 0) or not(a <= l)) end)


print 'OK'


A tests/5.1.5/constructs.lua => tests/5.1.5/constructs.lua +240 -0
@@ 0,0 1,240 @@
print "testing syntax"

-- testing priorities

assert(2^3^2 == 2^(3^2));
assert(2^3*4 == (2^3)*4);
assert(2^-2 == 1/4 and -2^- -2 == - - -4);
assert(not nil and 2 and not(2>3 or 3<2));
assert(-3-1-5 == 0+0-9);
assert(-2^2 == -4 and (-2)^2 == 4 and 2*2-3-1 == 0);
assert(2*1+3/3 == 3 and 1+2 .. 3*1 == "33");
assert(not(2+1 > 3*1) and "a".."b" > "a");

assert(not ((true or false) and nil))
assert(      true or false  and nil)

local a,b = 1,nil;
assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75);
x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);

x,y=1,2;
assert((x>y) and x or y == 2);
x,y=2,1;
assert((x>y) and x or y == 2);

assert(1234567890 == tonumber('1234567890') and 1234567890+1 == 1234567891)


-- silly loops
repeat until 1; repeat until true;
while false do end; while nil do end;

do  -- test old bug (first name could not be an `upvalue')
 local a; function f(x) x={a=1}; x={x=1}; x={G=1} end
end

function f (i)
  if type(i) ~= 'number' then return i,'jojo'; end;
  if i > 0 then return i, f(i-1); end;
end

x = {f(3), f(5), f(10);};
assert(x[1] == 3 and x[2] == 5 and x[3] == 10 and x[4] == 9 and x[12] == 1);
assert(x[nil] == nil)
x = {f'alo', f'xixi', nil};
assert(x[1] == 'alo' and x[2] == 'xixi' and x[3] == nil);
x = {f'alo'..'xixi'};
assert(x[1] == 'aloxixi')
x = {f{}}
assert(x[2] == 'jojo' and type(x[1]) == 'table')


local f = function (i)
  if i < 10 then return 'a';
  elseif i < 20 then return 'b';
  elseif i < 30 then return 'c';
  end;
end

assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)

for i=1,1000 do break; end;
n=100;
i=3;
t = {};
a=nil
while not a do
  a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end;
end
assert(a == n*(n+1)/2 and i==3);
assert(t[1] and t[n] and not t[0] and not t[n+1])

function f(b)
  local x = 1;
  repeat
    local a;
    if b==1 then local b=1; x=10; break
    elseif b==2 then x=20; break;
    elseif b==3 then x=30;
    else local a,b,c,d=math.sin(1); x=x+1;
    end
  until x>=12;
  return x;
end;

assert(f(1) == 10 and f(2) == 20 and f(3) == 30 and f(4)==12)


local f = function (i)
  if i < 10 then return 'a'
  elseif i < 20 then return 'b'
  elseif i < 30 then return 'c'
  else return 8
  end
end

assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == 8)

local a, b = nil, 23
x = {f(100)*2+3 or a, a or b+2}
assert(x[1] == 19 and x[2] == 25)
x = {f=2+3 or a, a = b+2}
assert(x.f == 5 and x.a == 25)

a={y=1}
x = {a.y}
assert(x[1] == 1)

function f(i)
  while 1 do
    if i>0 then i=i-1;
    else return; end;
  end;
end;

function g(i)
  while 1 do
    if i>0 then i=i-1
    else return end
  end
end

f(10); g(10);

do
  function f () return 1,2,3; end
  local a, b, c = f();
  assert(a==1 and b==2 and c==3)
  a, b, c = (f());
  assert(a==1 and b==nil and c==nil)
end

local a,b = 3 and f();
assert(a==1 and b==nil)

function g() f(); return; end;
assert(g() == nil)
function g() return nil or f() end
a,b = g()
assert(a==1 and b==nil)

print'+';


f = [[
return function ( a , b , c , d , e )
  local x = a >= b or c or ( d and e ) or nil
  return x
end , { a = 1 , b = 2 >= 1 , } or { 1 };
]]
f = string.gsub(f, "%s+", "\n");   -- force a SETLINE between opcodes
f,a = loadstring(f)();
assert(a.a == 1 and a.b)

function g (a,b,c,d,e)
  if not (a>=b or c or d and e or nil) then return 0; else return 1; end;
end

function h (a,b,c,d,e)
  while (a>=b or c or (d and e) or nil) do return 1; end;
  return 0;
end;

assert(f(2,1) == true and g(2,1) == 1 and h(2,1) == 1)
assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1)
assert(f(1,2,'a')
~=          -- force SETLINE before nil
nil, "")
assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1)
assert(f(1,2,nil,1,'x') == 'x' and g(1,2,nil,1,'x') == 1 and
                                   h(1,2,nil,1,'x') == 1)
assert(f(1,2,nil,nil,'x') == nil and g(1,2,nil,nil,'x') == 0 and
                                     h(1,2,nil,nil,'x') == 0)
assert(f(1,2,nil,1,nil) == nil and g(1,2,nil,1,nil) == 0 and
                                   h(1,2,nil,1,nil) == 0)

assert(1 and 2<3 == true and 2<3 and 'a'<'b' == true)
x = 2<3 and not 3; assert(x==false)
x = 2<1 or (2>1 and 'a'); assert(x=='a')


do
  local a; if nil then a=1; else a=2; end;    -- this nil comes as PUSHNIL 2
  assert(a==2)
end

function F(a)
  assert(debug.getinfo(1, "n").name == 'F')
  return a,2,3
end

a,b = F(1)~=nil; assert(a == true and b == nil);
a,b = F(nil)==nil; assert(a == true and b == nil)

----------------------------------------------------------------
-- creates all combinations of 
-- [not] ([not] arg op [not] (arg op [not] arg ))
-- and tests each one

function ID(x) return x end

function f(t, i)
  local b = t.n
  local res = math.mod(math.floor(i/c), b)+1
  c = c*b
  return t[res]
end

local arg = {" ( 1 < 2 ) ", " ( 1 >= 2 ) ", " F ( ) ", "  nil "; n=4}

local op = {" and ", " or ", " == ", " ~= "; n=4}

local neg = {" ", " not "; n=2}

local i = 0
repeat
  c = 1
  local s = f(neg, i)..'ID('..f(neg, i)..f(arg, i)..f(op, i)..
            f(neg, i)..'ID('..f(arg, i)..f(op, i)..f(neg, i)..f(arg, i)..'))'
  local s1 = string.gsub(s, 'ID', '')
  K,X,NX,WX1,WX2 = nil
  s = string.format([[
      local a = %s
      local b = not %s
      K = b
      local xxx; 
      if %s then X = a  else X = b end
      if %s then NX = b  else NX = a end
      while %s do WX1 = a; break end
      while %s do WX2 = a; break end
      repeat if (%s) then break end; assert(b)  until not(%s)
  ]], s1, s, s1, s, s1, s, s1, s, s)
  assert(loadstring(s))()
  assert(X and not NX and not WX1 == K and not WX2 == K)
  if math.mod(i,4000) == 0 then print('+') end
  i = i+1
until i==c

print'OK'

A tests/5.1.5/db.lua => tests/5.1.5/db.lua +499 -0
@@ 0,0 1,499 @@
-- testing debug library

local function dostring(s) return assert(loadstring(s))() end

print"testing debug library and debug information"

do
local a=1
end

function test (s, l, p)
  collectgarbage()   -- avoid gc during trace
  local function f (event, line)
    assert(event == 'line')
    local l = table.remove(l, 1)
    if p then print(l, line) end
    assert(l == line, "wrong trace!!")
  end
  debug.sethook(f,"l"); loadstring(s)(); debug.sethook()
  assert(table.getn(l) == 0)
end


do
  local a = debug.getinfo(print)
  assert(a.what == "C" and a.short_src == "[C]")
  local b = debug.getinfo(test, "SfL")
  assert(b.name == nil and b.what == "Lua" and b.linedefined == 11 and
         b.lastlinedefined == b.linedefined + 10 and
         b.func == test and not string.find(b.short_src, "%["))
  assert(b.activelines[b.linedefined + 1] and
         b.activelines[b.lastlinedefined])
  assert(not b.activelines[b.linedefined] and
         not b.activelines[b.lastlinedefined + 1])
end


-- test file and string names truncation
a = "function f () end"
local function dostring (s, x) return loadstring(s, x)() end
dostring(a)
assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
dostring(a..string.format("; %s\n=1", string.rep('p', 400)))
assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$'))
dostring("\n"..a)
assert(debug.getinfo(f).short_src == '[string "..."]')
dostring(a, "")
assert(debug.getinfo(f).short_src == '[string ""]')
dostring(a, "@xuxu")
assert(debug.getinfo(f).short_src == "xuxu")
dostring(a, "@"..string.rep('p', 1000)..'t')
assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$"))
dostring(a, "=xuxu")
assert(debug.getinfo(f).short_src == "xuxu")
dostring(a, string.format("=%s", string.rep('x', 500)))
assert(string.find(debug.getinfo(f).short_src, "^x*"))
dostring(a, "=")
assert(debug.getinfo(f).short_src == "")
a = nil; f = nil;


repeat
  local g = {x = function ()
    local a = debug.getinfo(2)
    assert(a.name == 'f' and a.namewhat == 'local')
    a = debug.getinfo(1)
    assert(a.name == 'x' and a.namewhat == 'field')
    return 'xixi'
  end}
  local f = function () return 1+1 and (not 1 or g.x()) end
  assert(f() == 'xixi')
  g = debug.getinfo(f)
  assert(g.what == "Lua" and g.func == f and g.namewhat == "" and not g.name)

  function f (x, name)   -- local!
    name = name or 'f'
    local a = debug.getinfo(1)
    assert(a.name == name and a.namewhat == 'local')
    return x
  end

  -- breaks in different conditions
  if 3>4 then break end; f()
  if 3<4 then a=1 else break end; f()
  while 1 do local x=10; break end; f()
  local b = 1
  if 3>4 then return math.sin(1) end; f()
  a = 3<4; f()
  a = 3<4 or 1; f()
  repeat local x=20; if 4>3 then f() else break end; f() until 1
  g = {}
  f(g).x = f(2) and f(10)+f(9)
  assert(g.x == f(19))
  function g(x) if not x then return 3 end return (x('a', 'x')) end
  assert(g(f) == 'a')
until 1

test([[if
math.sin(1)
then
  a=1
else
  a=2
end
]], {2,4,7})

test([[--
if nil then
  a=1
else
  a=2
end
]], {2,5,6})

test([[a=1
repeat
  a=a+1
until a==3
]], {1,3,4,3,4})

test([[ do
  return
end
]], {2})

test([[local a
a=1
while a<=3 do
  a=a+1
end
]], {2,3,4,3,4,3,4,3,5})

test([[while math.sin(1) do
  if math.sin(1)
  then
    break
  end
end
a=1]], {1,2,4,7})

test([[for i=1,3 do
  a=i
end
]], {1,2,1,2,1,2,1,3})

test([[for i,v in pairs{'a','b'} do
  a=i..v
end
]], {1,2,1,2,1,3})

test([[for i=1,4 do a=1 end]], {1,1,1,1,1})



print'+'

a = {}; L = nil
local glob = 1
local oldglob = glob
debug.sethook(function (e,l)
  collectgarbage()   -- force GC during a hook
  local f, m, c = debug.gethook()
  assert(m == 'crl' and c == 0)
  if e == "line" then
    if glob ~= oldglob then
      L = l-1   -- get the first line where "glob" has changed
      oldglob = glob
    end
  elseif e == "call" then
      local f = debug.getinfo(2, "f").func
      a[f] = 1
  else assert(e == "return")
  end
end, "crl")

function f(a,b)
  collectgarbage()
  local _, x = debug.getlocal(1, 1)
  local _, y = debug.getlocal(1, 2)
  assert(x == a and y == b)
  assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
  assert(debug.setlocal(2, 4, "ma��") == "B")
  x = debug.getinfo(2)
  assert(x.func == g and x.what == "Lua" and x.name == 'g' and
         x.nups == 0 and string.find(x.source, "^@.*db%.lua"))
  glob = glob+1
  assert(debug.getinfo(1, "l").currentline == L+1)
  assert(debug.getinfo(1, "l").currentline == L+2)
end

function foo()
  glob = glob+1
  assert(debug.getinfo(1, "l").currentline == L+1)
end; foo()  -- set L
-- check line counting inside strings and empty lines

_ = 'alo\
alo' .. [[

]]
--[[
]]
assert(debug.getinfo(1, "l").currentline == L+11)  -- check count of lines


function g(...)
  do local a,b,c; a=math.sin(40); end
  local feijao
  local AAAA,B = "xuxu", "mam�o"
  f(AAAA,B)
  assert(AAAA == "pera" and B == "ma��")
  do
     local B = 13
     local x,y = debug.getlocal(1,5)
     assert(x == 'B' and y == 13)
  end
end

g()


assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print])


-- tests for manipulating non-registered locals (C and Lua temporaries)

local n, v = debug.getlocal(0, 1)
assert(v == 0 and n == "(*temporary)")
local n, v = debug.getlocal(0, 2)
assert(v == 2 and n == "(*temporary)")
assert(not debug.getlocal(0, 3))
assert(not debug.getlocal(0, 0))

function f()
  assert(select(2, debug.getlocal(2,3)) == 1)
  assert(not debug.getlocal(2,4))
  debug.setlocal(2, 3, 10)
  return 20
end

function g(a,b) return (a+1) + f() end

assert(g(0,0) == 30)
 

debug.sethook(nil);
assert(debug.gethook() == nil)


-- testing access to function arguments

X = nil
a = {}
function a:f (a, b, ...) local c = 13 end
debug.sethook(function (e)
  assert(e == "call")
  dostring("XX = 12")  -- test dostring inside hooks
  -- testing errors inside hooks
  assert(not pcall(loadstring("a='joao'+1")))
  debug.sethook(function (e, l) 
    assert(debug.getinfo(2, "l").currentline == l)
    local f,m,c = debug.gethook()
    assert(e == "line")
    assert(m == 'l' and c == 0)
    debug.sethook(nil)  -- hook is called only once
    assert(not X)       -- check that
    X = {}; local i = 1
    local x,y
    while 1 do
      x,y = debug.getlocal(2, i)
      if x==nil then break end
      X[x] = y
      i = i+1
    end
  end, "l")
end, "c")

a:f(1,2,3,4,5)
assert(X.self == a and X.a == 1   and X.b == 2 and X.arg.n == 3 and X.c == nil)
assert(XX == 12)
assert(debug.gethook() == nil)


-- testing upvalue access
local function getupvalues (f)
  local t = {}
  local i = 1
  while true do
    local name, value = debug.getupvalue(f, i)
    if not name then break end
    assert(not t[name])
    t[name] = value
    i = i + 1
  end
  return t
end

local a,b,c = 1,2,3
local function foo1 (a) b = a; return c end
local function foo2 (x) a = x; return c+b end
assert(debug.getupvalue(foo1, 3) == nil)
assert(debug.getupvalue(foo1, 0) == nil)
assert(debug.setupvalue(foo1, 3, "xuxu") == nil)
local t = getupvalues(foo1)
assert(t.a == nil and t.b == 2 and t.c == 3)
t = getupvalues(foo2)
assert(t.a == 1 and t.b == 2 and t.c == 3)
assert(debug.setupvalue(foo1, 1, "xuxu") == "b")
assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu")
-- cannot manipulate C upvalues from Lua
assert(debug.getupvalue(io.read, 1) == nil)  
assert(debug.setupvalue(io.read, 1, 10) == nil)  


-- testing count hooks
local a=0
debug.sethook(function (e) a=a+1 end, "", 1)
a=0; for i=1,1000 do end; assert(1000 < a and a < 1012)
debug.sethook(function (e) a=a+1 end, "", 4)
a=0; for i=1,1000 do end; assert(250 < a and a < 255)
local f,m,c = debug.gethook()
assert(m == "" and c == 4)
debug.sethook(function (e) a=a+1 end, "", 4000)
a=0; for i=1,1000 do end; assert(a == 0)
debug.sethook(print, "", 2^24 - 1)   -- count upperbound
local f,m,c = debug.gethook()
assert(({debug.gethook()})[3] == 2^24 - 1)
debug.sethook()


-- tests for tail calls
local function f (x)
  if x then
    assert(debug.getinfo(1, "S").what == "Lua")
    local tail = debug.getinfo(2)
    assert(not pcall(getfenv, 3))
    assert(tail.what == "tail" and tail.short_src == "(tail call)" and
           tail.linedefined == -1 and tail.func == nil)
    assert(debug.getinfo(3, "f").func == g1)
    assert(getfenv(3))
    assert(debug.getinfo(4, "S").what == "tail")
    assert(not pcall(getfenv, 5))
    assert(debug.getinfo(5, "S").what == "main")
    assert(getfenv(5))
    print"+"
    end
end

function g(x) return f(x) end

function g1(x) g(x) end

local function h (x) local f=g1; return f(x) end

h(true)

local b = {}
debug.sethook(function (e) table.insert(b, e) end, "cr")
h(false)
debug.sethook()
local res = {"return",   -- first return (from sethook)
  "call", "call", "call", "call",
  "return", "tail return", "return", "tail return",
  "call",    -- last call (to sethook)
}
for _, k in ipairs(res) do assert(k == table.remove(b, 1)) end


lim = 30000
local function foo (x)
  if x==0 then
    assert(debug.getinfo(lim+2).what == "main")
    for i=2,lim do assert(debug.getinfo(i, "S").what == "tail") end
  else return foo(x-1)
  end
end

foo(lim)


print"+"


-- testing traceback

assert(debug.traceback(print) == print)
assert(debug.traceback(print, 4) == print)
assert(string.find(debug.traceback("hi", 4), "^hi\n"))
assert(string.find(debug.traceback("hi"), "^hi\n"))
assert(not string.find(debug.traceback("hi"), "'traceback'"))
assert(string.find(debug.traceback("hi", 0), "'traceback'"))
assert(string.find(debug.traceback(), "^stack traceback:\n"))

-- testing debugging of coroutines

local function checktraceback (co, p)
  local tb = debug.traceback(co)
  local i = 0
  for l in string.gmatch(tb, "[^\n]+\n?") do
    assert(i == 0 or string.find(l, p[i]))
    i = i+1
  end
  assert(p[i] == nil)
end


local function f (n)
  if n > 0 then return f(n-1)
  else coroutine.yield() end
end

local co = coroutine.create(f)
coroutine.resume(co, 3)
checktraceback(co, {"yield", "db.lua", "tail", "tail", "tail"})


co = coroutine.create(function (x)
       local a = 1
       coroutine.yield(debug.getinfo(1, "l"))
       coroutine.yield(debug.getinfo(1, "l").currentline)
       return a
     end)

local tr = {}
local foo = function (e, l) table.insert(tr, l) end
debug.sethook(co, foo, "l")

local _, l = coroutine.resume(co, 10)
local x = debug.getinfo(co, 1, "lfLS")
assert(x.currentline == l.currentline and x.activelines[x.currentline])
assert(type(x.func) == "function")
for i=x.linedefined + 1, x.lastlinedefined do
  assert(x.activelines[i])
  x.activelines[i] = nil
end
assert(next(x.activelines) == nil)   -- no 'extra' elements
assert(debug.getinfo(co, 2) == nil)
local a,b = debug.getlocal(co, 1, 1)
assert(a == "x" and b == 10)
a,b = debug.getlocal(co, 1, 2)
assert(a == "a" and b == 1)
debug.setlocal(co, 1, 2, "hi")
assert(debug.gethook(co) == foo)
assert(table.getn(tr) == 2 and
       tr[1] == l.currentline-1 and tr[2] == l.currentline)

a,b,c = pcall(coroutine.resume, co)
assert(a and b and c == l.currentline+1)
checktraceback(co, {"yield", "in function <"})

a,b = coroutine.resume(co)
assert(a and b == "hi")
assert(table.getn(tr) == 4 and tr[4] == l.currentline+2)
assert(debug.gethook(co) == foo)
assert(debug.gethook() == nil)
checktraceback(co, {})


-- check traceback of suspended (or dead with error) coroutines

function f(i) if i==0 then error(i) else coroutine.yield(); f(i-1) end end

co = coroutine.create(function (x) f(x) end)
a, b = coroutine.resume(co, 3)
t = {"'yield'", "'f'", "in function <"}
while coroutine.status(co) == "suspended" do
  checktraceback(co, t)
  a, b = coroutine.resume(co)
  table.insert(t, 2, "'f'")   -- one more recursive call to 'f'
end
t[1] = "'error'"
checktraceback(co, t)


-- test acessing line numbers of a coroutine from a resume inside
-- a C function (this is a known bug in Lua 5.0)

local function g(x)
    coroutine.yield(x)
end

local function f (i)
  debug.sethook(function () end, "l")
  for j=1,1000 do
    g(i+j)
  end
end

local co = coroutine.wrap(f)
co(10)
pcall(co)
pcall(co)


assert(type(debug.getregistry()) == "table")


print"OK"


A tests/5.1.5/errors.lua => tests/5.1.5/errors.lua +250 -0
@@ 0,0 1,250 @@
print("testing errors")

function doit (s)
  local f, msg = loadstring(s)
  if f == nil then return msg end
  local cond, msg = pcall(f)
  return (not cond) and msg
end


function checkmessage (prog, msg)
  assert(string.find(doit(prog), msg, 1, true))
end

function checksyntax (prog, extra, token, line)
  local msg = doit(prog)
  token = string.gsub(token, "(%p)", "%%%1")
  local pt = string.format([[^%%[string ".*"%%]:%d: .- near '%s'$]],
                           line, token)
  assert(string.find(msg, pt))
  assert(string.find(msg, msg, 1, true))
end


-- test error message with no extra info
assert(doit("error('hi', 0)") == 'hi')

-- test error message with no info
assert(doit("error()") == nil)


-- test common errors/errors that crashed in the past
assert(doit("unpack({}, 1, n=2^30)"))
assert(doit("a=math.sin()"))
assert(not doit("tostring(1)") and doit("tostring()"))
assert(doit"tonumber()")
assert(doit"repeat until 1; a")
checksyntax("break label", "", "label", 1)
assert(doit";")
assert(doit"a=1;;")
assert(doit"return;;")
assert(doit"assert(false)")
assert(doit"assert(nil)")
assert(doit"a=math.sin\n(3)")
assert(doit("function a (... , ...) end"))
assert(doit("function a (, ...) end"))

checksyntax([[
  local a = {4

]], "'}' expected (to close '{' at line 1)", "<eof>", 3)


-- tests for better error messages

checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'")
checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)",
       "local 'bbbb'")
checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'")
checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'"))
checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number")

aaa = nil
checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
checkmessage("local a,b,c; (function () a = b+1 end)()", "upvalue 'b'")
assert(not doit"local aaa={bbb={ddd=next}}; aaa.bbb:ddd(nil)")

checkmessage("b=1; local aaa='a'; x=aaa+b", "local 'aaa'")
checkmessage("aaa={}; x=3/aaa", "global 'aaa'")
checkmessage("aaa='2'; b=nil;x=aaa*b", "global 'b'")
checkmessage("aaa={}; x=-aaa", "global 'aaa'")
assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
assert(not string.find(doit"aaa={}; (aaa or aaa)()", "'aaa'"))

checkmessage([[aaa=9
repeat until 3==3
local x=math.sin(math.cos(3))
if math.sin(1) == x then return math.sin(1) end   -- tail call
local a,b = 1, {
  {x='a'..'b'..'c', y='b', z=x},
  {1,2,3,4,5} or 3+3<=3+3,
  3+1>3+1,
  {d = x and aaa[x or y]}}
]], "global 'aaa'")

checkmessage([[
local x,y = {},1
if math.sin(1) == 0 then return 3 end    -- return
x.a()]], "field 'a'")

checkmessage([[
prefix = nil
insert = nil
while 1 do  
  local a
  if nil then break end
  insert(prefix, a)
end]], "global 'insert'")

checkmessage([[  -- tail call
  return math.sin("a")
]], "'sin'")

checkmessage([[collectgarbage("nooption")]], "invalid option")

checkmessage([[x = print .. "a"]], "concatenate")

checkmessage("getmetatable(io.stdin).__gc()", "no value")

print'+'


-- testing line error

function lineerror (s)
  local err,msg = pcall(loadstring(s))
  local line = string.match(msg, ":(%d+):")
  return line and line+0
end

assert(lineerror"local a\n for i=1,'a' do \n print(i) \n end" == 2)
assert(lineerror"\n local a \n for k,v in 3 \n do \n print(k) \n end" == 3)
assert(lineerror"\n\n for k,v in \n 3 \n do \n print(k) \n end" == 4)
assert(lineerror"function a.x.y ()\na=a+1\nend" == 1)

local p = [[
function g() f() end
function f(x) error('a', X) end
g()
]]
X=3;assert(lineerror(p) == 3)
X=0;assert(lineerror(p) == nil)
X=1;assert(lineerror(p) == 2)
X=2;assert(lineerror(p) == 1)

lineerror = nil

C = 0
local l = debug.getinfo(1, "l").currentline; function y () C=C+1; y() end

local function checkstackmessage (m)
  return (string.find(m, "^.-:%d+: stack overflow"))
end
assert(checkstackmessage(doit('y()')))
assert(checkstackmessage(doit('y()')))
assert(checkstackmessage(doit('y()')))
-- teste de linhas em erro
C = 0
local l1
local function g()
  l1 = debug.getinfo(1, "l").currentline; y()
end
local _, stackmsg = xpcall(g, debug.traceback)
local stack = {}
for line in string.gmatch(stackmsg, "[^\n]*") do
  local curr = string.match(line, ":(%d+):")
  if curr then table.insert(stack, tonumber(curr)) end
end
local i=1
while stack[i] ~= l1 do
  assert(stack[i] == l)
  i = i+1
end
assert(i > 15)


-- error in error handling
local res, msg = xpcall(error, error)
assert(not res and type(msg) == 'string')

local function f (x)
  if x==0 then error('a\n')
  else
    local aux = function () return f(x-1) end
    local a,b = xpcall(aux, aux)
    return a,b
  end
end
f(3)

-- non string messages
function f() error{msg='x'} end
res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end)
assert(msg.msg == 'xy')

print('+')
checksyntax("syntax error", "", "error", 1)
checksyntax("1.000", "", "1.000", 1)
checksyntax("[[a]]", "", "[[a]]", 1)
checksyntax("'aa'", "", "'aa'", 1)

-- test 255 as first char in a chunk
checksyntax("\255a = 1", "", "\255", 1)

doit('I = loadstring("a=9+"); a=3')
assert(a==3 and I == nil)
print('+')

lim = 1000
if rawget(_G, "_soft") then lim = 100 end
for i=1,lim do
  doit('a = ')
  doit('a = 4+nil')
end


-- testing syntax limits
local function testrep (init, rep)
  local s = "local a; "..init .. string.rep(rep, 400)
  local a,b = loadstring(s)
  assert(not a and string.find(b, "syntax levels"))
end
testrep("a=", "{")
testrep("a=", "(")
testrep("", "a(")
testrep("", "do ")
testrep("", "while a do ")
testrep("", "if a then else ")
testrep("", "function foo () ")
testrep("a=", "a..")
testrep("a=", "a^")


-- testing other limits
-- upvalues
local  s = "function foo ()\n  local "
for j = 1,70 do
  s = s.."a"..j..", "
end
s = s.."b\n"
for j = 1,70 do
  s = s.."function foo"..j.." ()\n a"..j.."=3\n"
end
local a,b = loadstring(s)
assert(string.find(b, "line 3"))

-- local variables
s = "\nfunction foo ()\n  local "
for j = 1,300 do
  s = s.."a"..j..", " 
end
s = s.."b\n"
local a,b = loadstring(s)
assert(string.find(b, "line 2"))


print('OK')

A tests/5.1.5/etc/ltests.c => tests/5.1.5/etc/ltests.c +1147 -0
@@ 0,0 1,1147 @@
/*
** $Id: ltests.c,v 2.36 2006/01/10 13:13:06 roberto Exp $
** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/


#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ltests_c
#define LUA_CORE

#include "lua.h"

#include "lapi.h"
#include "lauxlib.h"
#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lmem.h"
#include "lopcodes.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "lualib.h"



/*
** The whole module only makes sense with LUA_DEBUG on
*/
#if defined(LUA_DEBUG)


int Trick = 0;


static lua_State *lua_state = NULL;

int islocked = 0;


#define obj_at(L,k)	(L->ci->base+(k) - 1)


static void setnameval (lua_State *L, const char *name, int val) {
  lua_pushstring(L, name);
  lua_pushinteger(L, val);
  lua_settable(L, -3);
}


/*
** {======================================================================
** Controlled version for realloc.
** =======================================================================
*/

#define MARK		0x55  /* 01010101 (a nice pattern) */

#ifndef EXTERNMEMCHECK
/* full memory check */
#define HEADER	(sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */
#define MARKSIZE	16  /* size of marks after each block */
#define blockhead(b)	(cast(char *, b) - HEADER)
#define setsize(newblock, size)	(*cast(size_t *, newblock) = size)
#define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b))))
#define fillmem(mem,size)	memset(mem, -MARK, size)
#else
/* external memory check: don't do it twice */
#define HEADER		0
#define MARKSIZE	0
#define blockhead(b)	(b)
#define setsize(newblock, size)	/* empty */
#define checkblocksize(b,size)	(1)
#define fillmem(mem,size)	/* empty */
#endif


Memcontrol memcontrol = {0L, 0L, 0L, ULONG_MAX};


static void *checkblock (void *block, size_t size) {
  void *b = blockhead(block);
  int i;
  for (i=0;i<MARKSIZE;i++)
    lua_assert(*(cast(char *, b)+HEADER+size+i) == MARK+i); /* corrupted block? */
  return b;
}


static void freeblock (Memcontrol *mc, void *block, size_t size) {
  if (block) {
    lua_assert(checkblocksize(block, size));
    block = checkblock(block, size);
    fillmem(block, size+HEADER+MARKSIZE);  /* erase block */
    free(block);  /* free original block */
    mc->numblocks--;
    mc->total -= size;
  }
}


void *debug_realloc (void *ud, void *block, size_t oldsize, size_t size) {
  Memcontrol *mc = cast(Memcontrol *, ud);
  lua_assert(oldsize == 0 || checkblocksize(block, oldsize));
  if (size == 0) {
    freeblock(mc, block, oldsize);
    return NULL;
  }
  else if (size > oldsize && mc->total+size-oldsize > mc->memlimit)
    return NULL;  /* to test memory allocation errors */
  else {
    void *newblock;
    int i;
    size_t realsize = HEADER+size+MARKSIZE;
    size_t commonsize = (oldsize < size) ? oldsize : size;
    if (realsize < size) return NULL;  /* overflow! */
    newblock = malloc(realsize);  /* alloc a new block */
    if (newblock == NULL) return NULL;
    if (block) {
      memcpy(cast(char *, newblock)+HEADER, block, commonsize);
      freeblock(mc, block, oldsize);  /* erase (and check) old copy */
    }
    /* initialize new part of the block with something `weird' */
    fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize);
    mc->total += size;
    if (mc->total > mc->maxmem)
      mc->maxmem = mc->total;
    mc->numblocks++;
    setsize(newblock, size);
    for (i=0;i<MARKSIZE;i++)
      *(cast(char *, newblock)+HEADER+size+i) = cast(char, MARK+i);
    return cast(char *, newblock)+HEADER;
  }
}


/* }====================================================================== */



/*
** {======================================================
** Functions to check memory consistency
** =======================================================
*/

static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
  if (isdead(g,t)) return 0;
  if (g->gcstate == GCSpropagate)
    return !isblack(f) || !iswhite(t);
  else if (g->gcstate == GCSfinalize)
    return iswhite(f);
  else
    return 1;
}


static void printobj (global_State *g, GCObject *o) {
  int i = 0;
  GCObject *p;
  for (p = g->rootgc; p != o && p != NULL; p = p->gch.next) i++;
  if (p == NULL) i = -1;
  printf("%d:%s(%p)-%c(%02X)", i, luaT_typenames[o->gch.tt], (void *)o,
           isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', o->gch.marked);
}


static int testobjref (global_State *g, GCObject *f, GCObject *t) {
  int r = testobjref1(g,f,t);
  if (!r) {
    printf("%d(%02X) - ", g->gcstate, g->currentwhite);
    printobj(g, f);
    printf("\t-> ");
    printobj(g, t);
    printf("\n");
  }
  return r;
}

#define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t)))

#define checkvalref(g,f,t) lua_assert(!iscollectable(t) || \
	((ttype(t) == (t)->value.gc->gch.tt) && testobjref(g,f,gcvalue(t))))



static void checktable (global_State *g, Table *h) {
  int i;
  int weakkey = 0;
  int weakvalue = 0;
  const TValue *mode;
  GCObject *hgc = obj2gco(h);
  if (h->metatable)
    checkobjref(g, hgc, h->metatable);
  mode = gfasttm(g, h->metatable, TM_MODE);
  if (mode && ttisstring(mode)) {  /* is there a weak mode? */
    weakkey = (strchr(svalue(mode), 'k') != NULL);
    weakvalue = (strchr(svalue(mode), 'v') != NULL);
  }
  i = h->sizearray;
  while (i--)
    checkvalref(g, hgc, &h->array[i]);
  i = sizenode(h);
  while (i--) {
    Node *n = gnode(h, i);
    if (!ttisnil(gval(n))) {
      lua_assert(!ttisnil(gkey(n)));
      checkvalref(g, hgc, gkey(n));
      checkvalref(g, hgc, gval(n));
    }
  }
}


/*
** All marks are conditional because a GC may happen while the
** prototype is still being created
*/
static void checkproto (global_State *g, Proto *f) {
  int i;
  GCObject *fgc = obj2gco(f);
  if (f->source) checkobjref(g, fgc, f->source);
  for (i=0; i<f->sizek; i++) {
    if (ttisstring(f->k+i))
      checkobjref(g, fgc, rawtsvalue(f->k+i));
  }
  for (i=0; i<f->sizeupvalues; i++) {
    if (f->upvalues[i])
      checkobjref(g, fgc, f->upvalues[i]);
  }
  for (i=0; i<f->sizep; i++) {
    if (f->p[i])
      checkobjref(g, fgc, f->p[i]);
  }
  for (i=0; i<f->sizelocvars; i++) {
    if (f->locvars[i].varname)
      checkobjref(g, fgc, f->locvars[i].varname);
  }
}



static void checkclosure (global_State *g, Closure *cl) {
  GCObject *clgc = obj2gco(cl);
  checkobjref(g, clgc, cl->l.env);
  if (cl->c.isC) {
    int i;
    for (i=0; i<cl->c.nupvalues; i++)
      checkvalref(g, clgc, &cl->c.upvalue[i]);
  }
  else {
    int i;
    lua_assert(cl->l.nupvalues == cl->l.p->nups);
    checkobjref(g, clgc, cl->l.p);
    for (i=0; i<cl->l.nupvalues; i++) {
      if (cl->l.upvals[i]) {
        lua_assert(cl->l.upvals[i]->tt == LUA_TUPVAL);
        checkobjref(g, clgc, cl->l.upvals[i]);
      }
    }
  }
}


static void checkstack (global_State *g, lua_State *L1) {
  StkId o;
  CallInfo *ci;
  GCObject *uvo;
  lua_assert(!isdead(g, obj2gco(L1)));
  for (uvo = L1->openupval; uvo != NULL; uvo = uvo->gch.next) {
    UpVal *uv = gco2uv(uvo);
    lua_assert(uv->v != &uv->u.value);  /* must be open */
    lua_assert(!isblack(uvo));  /* open upvalues cannot be black */
  }
  checkliveness(g, gt(L1));
  if (L1->base_ci) {
    for (ci = L1->base_ci; ci <= L1->ci; ci++) {
      lua_assert(ci->top <= L1->stack_last);
      lua_assert(lua_checkpc(L1, ci));
    }
  }
  else lua_assert(L1->size_ci == 0);
  if (L1->stack) {
    for (o = L1->stack; o < L1->top; o++)
      checkliveness(g, o);
  }
  else lua_assert(L1->stacksize == 0);
}


static void checkobject (global_State *g, GCObject *o) {
  if (isdead(g, o))
/*    lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);*/
{ if (!(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep))
printf(">>> %d  %s  %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marked);
}
  else {
    if (g->gcstate == GCSfinalize)
      lua_assert(iswhite(o));
    switch (o->gch.tt) {
      case LUA_TUPVAL: {
        UpVal *uv = gco2uv(o);
        lua_assert(uv->v == &uv->u.value);  /* must be closed */
        lua_assert(!isgray(o));  /* closed upvalues are never gray */
        checkvalref(g, o, uv->v);
        break;
      }
      case LUA_TUSERDATA: {
        Table *mt = gco2u(o)->metatable;
        if (mt) checkobjref(g, o, mt);
        break;
      }
      case LUA_TTABLE: {
        checktable(g, gco2h(o));
        break;
      }
      case LUA_TTHREAD: {
        checkstack(g, gco2th(o));
        break;
      }
      case LUA_TFUNCTION: {
        checkclosure(g, gco2cl(o));
        break;
      }
      case LUA_TPROTO: {
        checkproto(g, gco2p(o));
        break;
      }
      default: lua_assert(0);
    }
  }
}


int lua_checkpc (lua_State *L, pCallInfo ci) {
  if (ci == L->base_ci || !f_isLua(ci)) return 1;
  else {
    Proto *p = ci_func(ci)->l.p;
    if (ci < L->ci)
      return p->code <= ci->savedpc && ci->savedpc <= p->code + p->sizecode;
    else
      return p->code <= L->savedpc && L->savedpc <= p->code + p->sizecode;
  }
}


int lua_checkmemory (lua_State *L) {
  global_State *g = G(L);
  GCObject *o;
  UpVal *uv;
  checkstack(g, g->mainthread);
  for (o = g->rootgc; o != obj2gco(g->mainthread); o = o->gch.next)
    checkobject(g, o);
  for (o = o->gch.next; o != NULL; o = o->gch.next) {
    lua_assert(o->gch.tt == LUA_TUSERDATA);
    checkobject(g, o);
  }
  for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
    lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
    lua_assert(uv->v != &uv->u.value);  /* must be open */
    lua_assert(!isblack(obj2gco(uv)));  /* open upvalues are never black */
    checkvalref(g, obj2gco(uv), uv->v);
  }
  return 0;
}

/* }====================================================== */



/*
** {======================================================
** Disassembler
** =======================================================
*/


static char *buildop (Proto *p, int pc, char *buff) {
  Instruction i = p->code[pc];
  OpCode o = GET_OPCODE(i);
  const char *name = luaP_opnames[o];
  int line = getline(p, pc);
  sprintf(buff, "(%4d) %4d - ", line, pc);
  switch (getOpMode(o)) {  
    case iABC:
      sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name,
              GETARG_A(i), GETARG_B(i), GETARG_C(i));
      break;
    case iABx:
      sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i));
      break;
    case iAsBx:
      sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i));
      break;
  }
  return buff;
}


#if 0
void luaI_printcode (Proto *pt, int size) {
  int pc;
  for (pc=0; pc<size; pc++) {
    char buff[100];
    printf("%s\n", buildop(pt, pc, buff));
  }
  printf("-------\n");
}
#endif


static int listcode (lua_State *L) {
  int pc;
  Proto *p;
  luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
                 1, "Lua function expected");
  p = clvalue(obj_at(L, 1))->l.p;
  lua_newtable(L);
  setnameval(L, "maxstack", p->maxstacksize);
  setnameval(L, "numparams", p->numparams);
  for (pc=0; pc<p->sizecode; pc++) {
    char buff[100];
    lua_pushinteger(L, pc+1);
    lua_pushstring(L, buildop(p, pc, buff));
    lua_settable(L, -3);
  }
  return 1;
}


static int listk (lua_State *L) {
  Proto *p;
  int i;
  luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
                 1, "Lua function expected");
  p = clvalue(obj_at(L, 1))->l.p;
  lua_createtable(L, p->sizek, 0);
  for (i=0; i<p->sizek; i++) {
    luaA_pushobject(L, p->k+i);
    lua_rawseti(L, -2, i+1);
  }
  return 1;
}


static int listlocals (lua_State *L) {
  Proto *p;
  int pc = luaL_checkint(L, 2) - 1;
  int i = 0;
  const char *name;
  luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
                 1, "Lua function expected");
  p = clvalue(obj_at(L, 1))->l.p;
  while ((name = luaF_getlocalname(p, ++i, pc)) != NULL)
    lua_pushstring(L, name);
  return i-1;
}

/* }====================================================== */




static int get_limits (lua_State *L) {
  lua_createtable(L, 0, 5);
  setnameval(L, "BITS_INT", LUAI_BITSINT);
  setnameval(L, "LFPF", LFIELDS_PER_FLUSH);
  setnameval(L, "MAXVARS", LUAI_MAXVARS);
  setnameval(L, "MAXSTACK", MAXSTACK);
  setnameval(L, "MAXUPVALUES", LUAI_MAXUPVALUES);
  setnameval(L, "NUM_OPCODES", NUM_OPCODES);
  return 1;
}


static int mem_query (lua_State *L) {
  if (lua_isnone(L, 1)) {
    lua_pushinteger(L, memcontrol.total);
    lua_pushinteger(L, memcontrol.numblocks);
    lua_pushinteger(L, memcontrol.maxmem);
    return 3;
  }
  else {
    memcontrol.memlimit = luaL_checkint(L, 1);
    return 0;
  }
}


static int settrick (lua_State *L) {
  Trick = lua_tointeger(L, 1);
  return 0;
}


/*static int set_gcstate (lua_State *L) {
  static const char *const state[] = {"propagate", "sweep", "finalize"};
  return 0;
}*/


static int get_gccolor (lua_State *L) {
  TValue *o;
  luaL_checkany(L, 1);
  o = obj_at(L, 1);
  if (!iscollectable(o))
    lua_pushstring(L, "no collectable");
  else
    lua_pushstring(L, iswhite(gcvalue(o)) ? "white" :
                      isblack(gcvalue(o)) ? "black" : "grey");
  return 1;
}


static int gcstate (lua_State *L) {
  switch(G(L)->gcstate) {
    case GCSpropagate: lua_pushstring(L, "propagate"); break;
    case GCSsweepstring: lua_pushstring(L, "sweep strings"); break;
    case GCSsweep: lua_pushstring(L, "sweep"); break;
    case GCSfinalize: lua_pushstring(L, "finalize"); break;
  }
  return 1;
}


static int hash_query (lua_State *L) {
  if (lua_isnone(L, 2)) {
    luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected");
    lua_pushinteger(L, tsvalue(obj_at(L, 1))->hash);
  }
  else {
    TValue *o = obj_at(L, 1);
    Table *t;
    luaL_checktype(L, 2, LUA_TTABLE);
    t = hvalue(obj_at(L, 2));
    lua_pushinteger(L, luaH_mainposition(t, o) - t->node);
  }
  return 1;
}


static int stacklevel (lua_State *L) {
  unsigned long a = 0;
  lua_pushinteger(L, (L->top - L->stack));
  lua_pushinteger(L, (L->stack_last - L->stack));
  lua_pushinteger(L, (L->ci - L->base_ci));
  lua_pushinteger(L, (L->end_ci - L->base_ci));
  lua_pushinteger(L, (unsigned long)&a);
  return 5;
}


static int table_query (lua_State *L) {
  const Table *t;
  int i = luaL_optint(L, 2, -1);
  luaL_checktype(L, 1, LUA_TTABLE);
  t = hvalue(obj_at(L, 1));
  if (i == -1) {
    lua_pushinteger(L, t->sizearray);
    lua_pushinteger(L, luaH_isdummy(t->node) ? 0 : sizenode(t));
    lua_pushinteger(L, t->lastfree - t->node);
  }
  else if (i < t->sizearray) {
    lua_pushinteger(L, i);
    luaA_pushobject(L, &t->array[i]);
    lua_pushnil(L); 
  }
  else if ((i -= t->sizearray) < sizenode(t)) {
    if (!ttisnil(gval(gnode(t, i))) ||
        ttisnil(gkey(gnode(t, i))) ||
        ttisnumber(gkey(gnode(t, i)))) {
      luaA_pushobject(L, key2tval(gnode(t, i)));
    }
    else
      lua_pushliteral(L, "<undef>");
    luaA_pushobject(L, gval(gnode(t, i)));
    if (gnext(&t->node[i]))
      lua_pushinteger(L, gnext(&t->node[i]) - t->node);
    else
      lua_pushnil(L);
  }
  return 3;
}


static int string_query (lua_State *L) {
  stringtable *tb = &G(L)->strt;
  int s = luaL_optint(L, 2, 0) - 1;
  if (s==-1) {
    lua_pushinteger(L ,tb->nuse);
    lua_pushinteger(L ,tb->size);
    return 2;
  }
  else if (s < tb->size) {
    GCObject *ts;
    int n = 0;
    for (ts = tb->hash[s]; ts; ts = ts->gch.next) {
      setsvalue2s(L, L->top, gco2ts(ts));
      incr_top(L);
      n++;
    }
    return n;
  }
  return 0;
}


static int tref (lua_State *L) {
  int level = lua_gettop(L);
  int lock = luaL_optint(L, 2, 1);
  luaL_checkany(L, 1);
  lua_pushvalue(L, 1);
  lua_pushinteger(L, lua_ref(L, lock));
  lua_assert(lua_gettop(L) == level+1);  /* +1 for result */
  return 1;
}

static int getref (lua_State *L) {
  int level = lua_gettop(L);
  lua_getref(L, luaL_checkint(L, 1));
  lua_assert(lua_gettop(L) == level+1);
  return 1;
}

static int unref (lua_State *L) {
  int level = lua_gettop(L);
  lua_unref(L, luaL_checkint(L, 1));
  lua_assert(lua_gettop(L) == level);
  return 0;
}


static int upvalue (lua_State *L) {
  int n = luaL_checkint(L, 2);
  luaL_checktype(L, 1, LUA_TFUNCTION);
  if (lua_isnone(L, 3)) {
    const char *name = lua_getupvalue(L, 1, n);
    if (name == NULL) return 0;
    lua_pushstring(L, name);
    return 2;
  }
  else {
    const char *name = lua_setupvalue(L, 1, n);
    lua_pushstring(L, name);
    return 1;
  }
}


static int newuserdata (lua_State *L) {
  size_t size = luaL_checkint(L, 1);
  char *p = cast(char *, lua_newuserdata(L, size));
  while (size--) *p++ = '\0';
  return 1;
}


static int pushuserdata (lua_State *L) {
  lua_pushlightuserdata(L, cast(void *, luaL_checkint(L, 1)));
  return 1;
}


static int udataval (lua_State *L) {
  lua_pushinteger(L, cast(long, lua_touserdata(L, 1)));
  return 1;
}


static int doonnewstack (lua_State *L) {
  lua_State *L1 = lua_newthread(L);
  size_t l;
  const char *s = luaL_checklstring(L, 1, &l);
  int status = luaL_loadbuffer(L1, s, l, s);
  if (status == 0)
    status = lua_pcall(L1, 0, 0, 0);
  lua_pushinteger(L, status);
  return 1;
}


static int s2d (lua_State *L) {
  lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1)));
  return 1;
}


static int d2s (lua_State *L) {
  double d = luaL_checknumber(L, 1);
  lua_pushlstring(L, cast(char *, &d), sizeof(d));
  return 1;
}


static int num2int (lua_State *L) {
  lua_pushinteger(L, lua_tointeger(L, 1));
  return 1;
}


static int newstate (lua_State *L) {
  void *ud;
  lua_Alloc f = lua_getallocf(L, &ud);
  lua_State *L1 = lua_newstate(f, ud);
  if (L1)
    lua_pushinteger(L, (unsigned long)L1);
  else
    lua_pushnil(L);
  return 1;
}


static int loadlib (lua_State *L) {
  static const luaL_Reg libs[] = {
    {"baselibopen", luaopen_base},
    {"dblibopen", luaopen_debug},
    {"iolibopen", luaopen_io},
    {"mathlibopen", luaopen_math},
    {"strlibopen", luaopen_string},
    {"tablibopen", luaopen_table},
    {"packageopen", luaopen_package},
    {NULL, NULL}
  };
  lua_State *L1 = cast(lua_State *,
                       cast(unsigned long, luaL_checknumber(L, 1)));
  lua_pushvalue(L1, LUA_GLOBALSINDEX);
  luaL_register(L1, NULL, libs);
  return 0;
}

static int closestate (lua_State *L) {
  lua_State *L1 = cast(lua_State *, cast(unsigned long, luaL_checknumber(L, 1)));
  lua_close(L1);
  return 0;
}

static int doremote (lua_State *L) {
  lua_State *L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1)));
  size_t lcode;
  const char *code = luaL_checklstring(L, 2, &lcode);
  int status;
  lua_settop(L1, 0);
  status = luaL_loadbuffer(L1, code, lcode, code);
  if (status == 0)
    status = lua_pcall(L1, 0, LUA_MULTRET, 0);
  if (status != 0) {
    lua_pushnil(L);
    lua_pushinteger(L, status);
    lua_pushstring(L, lua_tostring(L1, -1));
    return 3;
  }
  else {
    int i = 0;
    while (!lua_isnone(L1, ++i))
      lua_pushstring(L, lua_tostring(L1, i));
    lua_pop(L1, i-1);
    return i-1;
  }
}


static int log2_aux (lua_State *L) {
  lua_pushinteger(L, luaO_log2(luaL_checkint(L, 1)));
  return 1;
}

static int int2fb_aux (lua_State *L) {
  int b = luaO_int2fb(luaL_checkint(L, 1));
  lua_pushinteger(L, b);
  lua_pushinteger(L, luaO_fb2int(b));
  return 2;
}



/*
** {======================================================
** function to test the API with C. It interprets a kind of assembler
** language with calls to the API, so the test can be driven by Lua code
** =======================================================
*/

static const char *const delimits = " \t\n,;";

static void skip (const char **pc) {
  while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++;
}

static int getnum_aux (lua_State *L, const char **pc) {
  int res = 0;
  int sig = 1;
  skip(pc);
  if (**pc == '.') {
    res = cast_int(lua_tonumber(L, -1));
    lua_pop(L, 1);
    (*pc)++;
    return res;
  }
  else if (**pc == '-') {
    sig = -1;
    (*pc)++;
  }
  while (isdigit(cast_int(**pc))) res = res*10 + (*(*pc)++) - '0';
  return sig*res;
}
  
static const char *getname_aux (char *buff, const char **pc) {
  int i = 0;
  skip(pc);
  while (**pc != '\0' && !strchr(delimits, **pc))
    buff[i++] = *(*pc)++;
  buff[i] = '\0';
  return buff;
}


static int getindex_aux (lua_State *L, const char **pc) {
  skip(pc);
  switch (*(*pc)++) {
    case 'R': return LUA_REGISTRYINDEX;
    case 'G': return LUA_GLOBALSINDEX;
    case 'E': return LUA_ENVIRONINDEX;
    case 'U': return lua_upvalueindex(getnum_aux(L, pc));
    default: (*pc)--; return getnum_aux(L, pc);
  }
}

#define EQ(s1)	(strcmp(s1, inst) == 0)

#define getnum	(getnum_aux(L, &pc))
#define getname	(getname_aux(buff, &pc))
#define getindex (getindex_aux(L, &pc))


static int testC (lua_State *L) {
  char buff[30];
  lua_State *L1;
  const char *pc;
  if (lua_isnumber(L, 1)) {
    L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1)));
    pc = luaL_checkstring(L, 2);
  }
  else {
    L1 = L;
    pc = luaL_checkstring(L, 1);
  }
  for (;;) {
    const char *inst = getname;
    if EQ("") return 0;
    else if EQ("isnumber") {
      lua_pushinteger(L1, lua_isnumber(L1, getindex));
    }
    else if EQ("isstring") {
      lua_pushinteger(L1, lua_isstring(L1, getindex));
    }
    else if EQ("istable") {
      lua_pushinteger(L1, lua_istable(L1, getindex));
    }
    else if EQ("iscfunction") {
      lua_pushinteger(L1, lua_iscfunction(L1, getindex));
    }
    else if EQ("isfunction") {
      lua_pushinteger(L1, lua_isfunction(L1, getindex));
    }
    else if EQ("isuserdata") {
      lua_pushinteger(L1, lua_isuserdata(L1, getindex));
    }
    else if EQ("isudataval") {
      lua_pushinteger(L1, lua_islightuserdata(L1, getindex));
    }
    else if EQ("isnil") {
      lua_pushinteger(L1, lua_isnil(L1, getindex));
    }
    else if EQ("isnull") {
      lua_pushinteger(L1, lua_isnone(L1, getindex));
    }
    else if EQ("tonumber") {
      lua_pushnumber(L1, lua_tonumber(L1, getindex));
    }
    else if EQ("tostring") {
      const char *s = lua_tostring(L1, getindex);
      lua_pushstring(L1, s);
    }
    else if EQ("objsize") {
      lua_pushinteger(L1, lua_objlen(L1, getindex));
    }
    else if EQ("tocfunction") {
      lua_pushcfunction(L1, lua_tocfunction(L1, getindex));
    }
    else if EQ("return") {
      return getnum;
    }
    else if EQ("gettop") {
      lua_pushinteger(L1, lua_gettop(L1));
    }
    else if EQ("settop") {
      lua_settop(L1, getnum);
    }
    else if EQ("pop") {
      lua_pop(L1, getnum);
    }
    else if EQ("pushnum") {
      lua_pushinteger(L1, getnum);
    }
    else if EQ("pushstring") {
      lua_pushstring(L1, getname);
    }
    else if EQ("pushnil") {
      lua_pushnil(L1);
    }
    else if EQ("pushbool") {
      lua_pushboolean(L1, getnum);
    }
    else if EQ("newuserdata") {
      lua_newuserdata(L1, getnum);
    }
    else if EQ("tobool") {
      lua_pushinteger(L1, lua_toboolean(L1, getindex));
    }
    else if EQ("pushvalue") {
      lua_pushvalue(L1, getindex);
    }
    else if EQ("pushcclosure") {
      lua_pushcclosure(L1, testC, getnum);
    }
    else if EQ("remove") {
      lua_remove(L1, getnum);
    }
    else if EQ("insert") {
      lua_insert(L1, getnum);
    }
    else if EQ("replace") {
      lua_replace(L1, getindex);
    }
    else if EQ("gettable") {
      lua_gettable(L1, getindex);
    }
    else if EQ("settable") {
      lua_settable(L1, getindex);
    }
    else if EQ("next") {
      lua_next(L1, -2);
    }
    else if EQ("concat") {
      lua_concat(L1, getnum);
    }
    else if EQ("lessthan") {
      int a = getindex;
      lua_pushboolean(L1, lua_lessthan(L1, a, getindex));
    }
    else if EQ("equal") {
      int a = getindex;
      lua_pushboolean(L1, lua_equal(L1, a, getindex));
    }
    else if EQ("rawcall") {
      int narg = getnum;
      int nres = getnum;
      lua_call(L1, narg, nres);
    }
    else if EQ("call") {
      int narg = getnum;
      int nres = getnum;
      lua_pcall(L1, narg, nres, 0);
    }
    else if EQ("loadstring") {
      size_t sl;
      const char *s = luaL_checklstring(L1, getnum, &sl);
      luaL_loadbuffer(L1, s, sl, s);
    }
    else if EQ("loadfile") {
      luaL_loadfile(L1, luaL_checkstring(L1, getnum));
    }
    else if EQ("setmetatable") {
      lua_setmetatable(L1, getindex);
    }
    else if EQ("getmetatable") {
      if (lua_getmetatable(L1, getindex) == 0)
        lua_pushnil(L1);
    }
    else if EQ("type") {
      lua_pushstring(L1, luaL_typename(L1, getnum));
    }
    else if EQ("getn") {
      int i = getindex;
      lua_pushinteger(L1, luaL_getn(L1, i));
    }
#ifndef luaL_setn
    else if EQ("setn") {
      int i = getindex;
      int n = cast_int(lua_tonumber(L1, -1));
      luaL_setn(L1, i, n);
      lua_pop(L1, 1);
    }
#endif
    else if EQ("throw") {
#if defined(__cplusplus)
static struct X { int x; } x;
      throw x;
#else
      luaL_error(L1, "C++");
#endif
      break;
    }
    else luaL_error(L, "unknown instruction %s", buff);
  }
  return 0;
}

/* }====================================================== */


/*
** {======================================================
** tests for yield inside hooks
** =======================================================
*/

static void yieldf (lua_State *L, lua_Debug *ar) {
  lua_yield(L, 0);
}

static int setyhook (lua_State *L) {
  if (lua_isnoneornil(L, 1))
    lua_sethook(L, NULL, 0, 0);  /* turn off hooks */
  else {
    const char *smask = luaL_checkstring(L, 1);
    int count = luaL_optint(L, 2, 0);
    int mask = 0;
    if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
    if (count > 0) mask |= LUA_MASKCOUNT;
    lua_sethook(L, yieldf, mask, count);
  }
  return 0;
}


static int coresume (lua_State *L) {
  int status;
  lua_State *co = lua_tothread(L, 1);
  luaL_argcheck(L, co, 1, "coroutine expected");
  status = lua_resume(co, 0);
  if (status != 0) {
    lua_pushboolean(L, 0);
    lua_insert(L, -2);
    return 2;  /* return false + error message */
  }
  else {
    lua_pushboolean(L, 1);
    return 1;
  }
}

/* }====================================================== */



/*
** {======================================================
** tests auxlib functions
** =======================================================
*/

static int auxgsub (lua_State *L) {
  const char *s1 = luaL_checkstring(L, 1);
  const char *s2 = luaL_checkstring(L, 2);
  const char *s3 = luaL_checkstring(L, 3);
  lua_settop(L, 3);
  luaL_gsub(L, s1, s2, s3);
  lua_assert(lua_gettop(L) == 4);
  return 1;
}


/* }====================================================== */



static const struct luaL_Reg tests_funcs[] = {
  {"checkmemory", lua_checkmemory},
  {"closestate", closestate},
  {"d2s", d2s},
  {"doonnewstack", doonnewstack},
  {"doremote", doremote},
  {"gccolor", get_gccolor},
  {"gcstate", gcstate},
  {"getref", getref},
  {"gsub", auxgsub},
  {"hash", hash_query},
  {"int2fb", int2fb_aux},
  {"limits", get_limits},
  {"listcode", listcode},
  {"listk", listk},
  {"listlocals", listlocals},
  {"loadlib", loadlib},
  {"log2", log2_aux},
  {"newstate", newstate},
  {"newuserdata", newuserdata},
  {"num2int", num2int},
  {"pushuserdata", pushuserdata},
  {"querystr", string_query},
  {"querytab", table_query},
  {"ref", tref},
  {"resume", coresume},
  {"s2d", s2d},
  {"setyhook", setyhook},
  {"stacklevel", stacklevel},
  {"testC", testC},
  {"totalmem", mem_query},
  {"trick", settrick},
  {"udataval", udataval},
  {"unref", unref},
  {"upvalue", upvalue},
  {NULL, NULL}
};


int luaB_opentests (lua_State *L) {
  void *ud;
  lua_assert(lua_getallocf(L, &ud) == debug_realloc);
  lua_assert(ud == cast(void *, &memcontrol));
  lua_setallocf(L, lua_getallocf(L, NULL), ud);
  lua_state = L;  /* keep first state to be opened */
  luaL_register(L, "T", tests_funcs);
  return 0;
}


#undef main
int main (int argc, char *argv[]) {
  int ret;
  char *limit = getenv("MEMLIMIT");
  if (limit)
    memcontrol.memlimit = strtoul(limit, NULL, 10);
  ret = l_main(argc, argv);
  lua_assert(memcontrol.numblocks == 0);
  lua_assert(memcontrol.total == 0);
  return ret;
}

#endif

A tests/5.1.5/etc/ltests.h => tests/5.1.5/etc/ltests.h +92 -0
@@ 0,0 1,92 @@
/*
** $Id: ltests.h,v 2.17 2005/12/27 17:12:00 roberto Exp $
** Internal Header for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/

#ifndef ltests_h
#define ltests_h


#include <stdlib.h>


#define LUA_DEBUG

#undef NDEBUG
#include <assert.h>
#define lua_assert(c)           assert(c)


/* to avoid warnings, and to make sure value is really unused */
#define UNUSED(x)       (x=0, (void)(x))


/* memory allocator control variables */
typedef struct Memcontrol {
  unsigned long numblocks;
  unsigned long total;
  unsigned long maxmem;
  unsigned long memlimit;
} Memcontrol;

LUAI_DATA Memcontrol memcontrol;


/*
** generic variable for debug tricks
*/
LUAI_DATA int Trick;


void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize);

#ifdef lua_c
#define luaL_newstate()	lua_newstate(debug_realloc, &memcontrol)
#endif


typedef struct CallInfo *pCallInfo;

int lua_checkmemory (lua_State *L);
int lua_checkpc (lua_State *L, pCallInfo ci);


/* test for lock/unlock */
#undef luai_userstateopen
#undef luai_userstatethread
#undef lua_lock
#undef lua_unlock
#undef LUAI_EXTRASPACE

struct L_EXTRA { int lock; int *plock; };
#define LUAI_EXTRASPACE		sizeof(struct L_EXTRA)
#define getlock(l)	(cast(struct L_EXTRA *, l) - 1)
#define luai_userstateopen(l)  \
	(getlock(l)->lock = 0, getlock(l)->plock = &(getlock(l)->lock))
#define luai_userstatethread(l,l1)  (getlock(l1)->plock = getlock(l)->plock)
#define lua_lock(l)     lua_assert((*getlock(l)->plock)++ == 0)
#define lua_unlock(l)   lua_assert(--(*getlock(l)->plock) == 0)


int luaB_opentests (lua_State *L);

#ifdef lua_c
#define luaL_openlibs(L)	{ (luaL_openlibs)(L); luaB_opentests(L); }
#endif



/* real main will be defined at `ltests.c' */
int l_main (int argc, char *argv[]);
#define main	l_main



/* change some sizes to give some bugs a chance */

#undef LUAL_BUFFERSIZE
#define LUAL_BUFFERSIZE		27
#define MINSTRTABSIZE		2

#endif

A tests/5.1.5/events.lua => tests/5.1.5/events.lua +360 -0
@@ 0,0 1,360 @@
print('testing metatables')

X = 20; B = 30

setfenv(1, setmetatable({}, {__index=_G}))

collectgarbage()

X = X+10
assert(X == 30 and _G.X == 20)
B = false
assert(B == false)
B = nil
assert(B == 30)

assert(getmetatable{} == nil)
assert(getmetatable(4) == nil)
assert(getmetatable(nil) == nil)
a={}; setmetatable(a, {__metatable = "xuxu",
                    __tostring=function(x) return x.name end})
assert(getmetatable(a) == "xuxu")
assert(tostring(a) == nil)
-- cannot change a protected metatable
assert(pcall(setmetatable, a, {}) == false)
a.name = "gororoba"
assert(tostring(a) == "gororoba")

local a, t = {10,20,30; x="10", y="20"}, {}
assert(setmetatable(a,t) == a)
assert(getmetatable(a) == t)
assert(setmetatable(a,nil) == a)
assert(getmetatable(a) == nil)
assert(setmetatable(a,t) == a)


function f (t, i, e)
  assert(not e)
  local p = rawget(t, "parent")
  return (p and p[i]+3), "dummy return"
end

t.__index = f

a.parent = {z=25, x=12, [4] = 24}
assert(a[1] == 10 and a.z == 28 and a[4] == 27 and a.x == "10")

collectgarbage()

a = setmetatable({}, t)
function f(t, i, v) rawset(t, i, v-3) end
t.__newindex = f
a[1] = 30; a.x = "101"; a[5] = 200
assert(a[1] == 27 and a.x == 98 and a[5] == 197)


local c = {}
a = setmetatable({}, t)
t.__newindex = c
a[1] = 10; a[2] = 20; a[3] = 90
assert(c[1] == 10 and c[2] == 20 and c[3] == 90)


do
  local a;
  a = setmetatable({}, {__index = setmetatable({},
                     {__index = setmetatable({},
                     {__index = function (_,n) return a[n-3]+4, "lixo" end})})})
  a[0] = 20
  for i=0,10 do
    assert(a[i*3] == 20 + i*4)
  end
end


do  -- newindex
  local foi
  local a = {}
  for i=1,10 do a[i] = 0; a['a'..i] = 0; end
  setmetatable(a, {__newindex = function (t,k,v) foi=true; rawset(t,k,v) end})
  foi = false; a[1]=0; assert(not foi)
  foi = false; a['a1']=0; assert(not foi)
  foi = false; a['a11']=0; assert(foi)
  foi = false; a[11]=0; assert(foi)
  foi = false; a[1]=nil; assert(not foi)
  foi = false; a[1]=nil; assert(foi)
end


function f (t, ...) return t, {...} end
t.__call = f

do
  local x,y = a(unpack{'a', 1})
  assert(x==a and y[1]=='a' and y[2]==1 and y[3]==nil)
  x,y = a()
  assert(x==a and y[1]==nil)
end


local b = setmetatable({}, t)
setmetatable(b,t)

function f(op)
  return function (...) cap = {[0] = op, ...} ; return (...) end
end
t.__add = f("add")
t.__sub = f("sub")
t.__mul = f("mul")
t.__div = f("div")
t.__mod = f("mod")
t.__unm = f("unm")
t.__pow = f("pow")

assert(b+5 == b)
assert(cap[0] == "add" and cap[1] == b and cap[2] == 5 and cap[3]==nil)
assert(b+'5' == b)
assert(cap[0] == "add" and cap[1] == b and cap[2] == '5' and cap[3]==nil)
assert(5+b == 5)
assert(cap[0] == "add" and cap[1] == 5 and cap[2] == b and cap[3]==nil)
assert('5'+b == '5')
assert(cap[0] == "add" and cap[1] == '5' and cap[2] == b and cap[3]==nil)
b=b-3; assert(getmetatable(b) == t)
assert(5-a == 5)
assert(cap[0] == "sub" and cap[1] == 5 and cap[2] == a and cap[3]==nil)
assert('5'-a == '5')
assert(cap[0] == "sub" and cap[1] == '5' and cap[2] == a and cap[3]==nil)
assert(a*a == a)
assert(cap[0] == "mul" and cap[1] == a and cap[2] == a and cap[3]==nil)
assert(a/0 == a)
assert(cap[0] == "div" and cap[1] == a and cap[2] == 0 and cap[3]==nil)
assert(a%2 == a)
assert(cap[0] == "mod" and cap[1] == a and cap[2] == 2 and cap[3]==nil)
assert(-a == a)
assert(cap[0] == "unm" and cap[1] == a)
assert(a^4 == a)
assert(cap[0] == "pow" and cap[1] == a and cap[2] == 4 and cap[3]==nil)
assert(a^'4' == a)
assert(cap[0] == "pow" and cap[1] == a and cap[2] == '4' and cap[3]==nil)
assert(4^a == 4)
assert(cap[0] == "pow" and cap[1] == 4 and cap[2] == a and cap[3]==nil)
assert('4'^a == '4')
assert(cap[0] == "pow" and cap[1] == '4' and cap[2] == a and cap[3]==nil)


t = {}
t.__lt = function (a,b,c)
  collectgarbage()
  assert(c == nil)
  if type(a) == 'table' then a = a.x end
  if type(b) == 'table' then b = b.x end
 return a<b, "dummy"
end

function Op(x) return setmetatable({x=x}, t) end

local function test ()
  assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1)))
  assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a')))
  assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1)))
  assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a')))
  assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1)))
  assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a')))
  assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1)))
  assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a')))
end

test()

t.__le = function (a,b,c)
  assert(c == nil)
  if type(a) == 'table' then a = a.x end
  if type(b) == 'table' then b = b.x end
 return a<=b, "dummy"
end

test()  -- retest comparisons, now using both `lt' and `le'


-- test `partial order'

local function Set(x)
  local y = {}
  for _,k in pairs(x) do y[k] = 1 end
  return setmetatable(y, t)
end

t.__lt = function (a,b)
  for k in pairs(a) do
    if not b[k] then return false end
    b[k] = nil
  end
  return next(b) ~= nil
end

t.__le = nil

assert(Set{1,2,3} < Set{1,2,3,4})
assert(not(Set{1,2,3,4} < Set{1,2,3,4}))
assert((Set{1,2,3,4} <= Set{1,2,3,4}))
assert((Set{1,2,3,4} >= Set{1,2,3,4}))
assert((Set{1,3} <= Set{3,5}))   -- wrong!! model needs a `le' method ;-)

t.__le = function (a,b)
  for k in pairs(a) do
    if not b[k] then return false end
  end
  return true
end

assert(not (Set{1,3} <= Set{3,5}))   -- now its OK!
assert(not(Set{1,3} <= Set{3,5}))
assert(not(Set{1,3} >= Set{3,5}))

t.__eq = function (a,b)
  for k in pairs(a) do
    if not b[k] then return false end
    b[k] = nil
  end
  return next(b) == nil
end

local s = Set{1,3,5}
assert(s == Set{3,5,1})
assert(not rawequal(s, Set{3,5,1}))
assert(rawequal(s, s))
assert(Set{1,3,5,1} == Set{3,5,1})
assert(Set{1,3,5} ~= Set{3,5,1,6})
t[Set{1,3,5}] = 1
assert(t[Set{1,3,5}] == nil)   -- `__eq' is not valid for table accesses


t.__concat = function (a,b,c)
  assert(c == nil)
  if type(a) == 'table' then a = a.val end
  if type(b) == 'table' then b = b.val end
  if A then return a..b
  else
    return setmetatable({val=a..b}, t)
  end
end

c = {val="c"}; setmetatable(c, t)
d = {val="d"}; setmetatable(d, t)

A = true
assert(c..d == 'cd')
assert(0 .."a".."b"..c..d.."e".."f"..(5+3).."g" == "0abcdef8g")

A = false
x = c..d
assert(getmetatable(x) == t and x.val == 'cd')
x = 0 .."a".."b"..c..d.."e".."f".."g"
assert(x.val == "0abcdefg")


-- test comparison compatibilities
local t1, t2, c, d
t1 = {};  c = {}; setmetatable(c, t1)
d = {}
t1.__eq = function () return true end
t1.__lt = function () return true end
assert(c ~= d and not pcall(function () return c < d end))
setmetatable(d, t1)
assert(c == d and c < d and not(d <= c))
t2 = {}
t2.__eq = t1.__eq
t2.__lt = t1.__lt
setmetatable(d, t2)
assert(c == d and c < d and not(d <= c))



-- test for several levels of calls
local i
local tt = {
  __call = function (t, ...)
    i = i+1
    if t.f then return t.f(...)
    else return {...}
    end
  end
}

local a = setmetatable({}, tt)
local b = setmetatable({f=a}, tt)
local c = setmetatable({f=b}, tt)

i = 0
x = c(3,4,5)
assert(i == 3 and x[1] == 3 and x[3] == 5)


assert(_G.X == 20)
assert(_G == getfenv(0))

print'+'

local _g = _G
setfenv(1, setmetatable({}, {__index=function (_,k) return _g[k] end}))

-- testing proxies
assert(getmetatable(newproxy()) == nil)
assert(getmetatable(newproxy(false)) == nil)

local u = newproxy(true)

getmetatable(u).__newindex = function (u,k,v)
  getmetatable(u)[k] = v
end

getmetatable(u).__index = function (u,k)
  return getmetatable(u)[k]
end

for i=1,10 do u[i] = i end
for i=1,10 do assert(u[i] == i) end

local k = newproxy(u)
assert(getmetatable(k) == getmetatable(u))


a = {}
rawset(a, "x", 1, 2, 3)
assert(a.x == 1 and rawget(a, "x", 3) == 1)

print '+'

-- testing metatables for basic types
mt = {}
debug.setmetatable(10, mt)
assert(getmetatable(-2) == mt)
mt.__index = function (a,b) return a+b end
assert((10)[3] == 13)
assert((10)["3"] == 13)
debug.setmetatable(23, nil)
assert(getmetatable(-2) == nil)

debug.setmetatable(true, mt)
assert(getmetatable(false) == mt)
mt.__index = function (a,b) return a or b end
assert((true)[false] == true)
assert((false)[false] == false)
debug.setmetatable(false, nil)
assert(getmetatable(true) == nil)

debug.setmetatable(nil, mt)
assert(getmetatable(nil) == mt)
mt.__add = function (a,b) return (a or 0) + (b or 0) end
assert(10 + nil == 10)
assert(nil + 23 == 23)
assert(nil + nil == 0)
debug.setmetatable(nil, nil)
assert(getmetatable(nil) == nil)

debug.setmetatable(nil, {})


print 'OK'

return 12

A tests/5.1.5/files.lua => tests/5.1.5/files.lua +324 -0
@@ 0,0 1,324 @@

print('testing i/o')

assert(io.input(io.stdin) == io.stdin)
assert(io.output(io.stdout) == io.stdout)


assert(type(io.input()) == "userdata" and io.type(io.output()) == "file")
assert(io.type(8) == nil)
local a = {}; setmetatable(a, {})
assert(io.type(a) == nil)

local a,b,c = io.open('xuxu_nao_existe')
assert(not a and type(b) == "string" and type(c) == "number")

a,b,c = io.open('/a/b/c/d', 'w')
assert(not a and type(b) == "string" and type(c) == "number")

local file = os.tmpname()
local otherfile = os.tmpname()

assert(os.setlocale('C', 'all'))

io.input(io.stdin); io.output(io.stdout);

os.remove(file)
assert(loadfile(file) == nil)
assert(io.open(file) == nil)
io.output(file)
assert(io.output() ~= io.stdout)

assert(io.output():seek() == 0)
assert(io.write("alo alo"))
assert(io.output():seek() == string.len("alo alo"))
assert(io.output():seek("cur", -3) == string.len("alo alo")-3)
assert(io.write("joao"))
assert(io.output():seek("end") == string.len("alo joao"))

assert(io.output():seek("set") == 0)

assert(io.write('"�lo"', "{a}\n", "second line\n", "third line \n"))
assert(io.write('�fourth_line'))
io.output(io.stdout)
collectgarbage()  -- file should be closed by GC
assert(io.input() == io.stdin and rawequal(io.output(), io.stdout))
print('+')

-- test GC for files
collectgarbage()
for i=1,120 do
  for i=1,5 do
    io.input(file)
    assert(io.open(file, 'r'))
    io.lines(file)
  end
  collectgarbage()
end

assert(os.rename(file, otherfile))
assert(os.rename(file, otherfile) == nil)

io.output(io.open(otherfile, "a"))
assert(io.write("\n\n\t\t  3450\n"));
io.close()

-- test line generators
assert(os.rename(otherfile, file))
io.output(otherfile)
local f = io.lines(file)
while f() do end;
assert(not pcall(f))  -- read lines after EOF
assert(not pcall(f))  -- read lines after EOF
-- copy from file to otherfile
for l in io.lines(file) do io.write(l, "\n") end
io.close()
-- copy from otherfile back to file
local f = assert(io.open(otherfile))
assert(io.type(f) == "file")
io.output(file)
assert(io.output():read() == nil)