---
source: src/main.rs
expression: compiled
input_file: test-data/lua5.1-tests/api.lua
---
if T == nil {
(Message || print)('\a\n >>> testC not active: skipping API tests <<<\n\a');
return
}
global fn tcheck(t1, t2) {
table.remove(t1, 1);
assert(table.getn(t1) == table.getn(t2));
for i = 1, table.getn(t1) {
assert(t1[(i)] == t2[(i)]);
}
}
global fn pack(...) {
return arg
}
print('testing C API');
a = T.d2s(12458954321123)
assert(string.len(a) == 8);
assert(T.s2d(a) == 12458954321123);
a, b, c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
assert(a == 2 && b == 3 && !c);
a, b, c = T.testC("pushbool 1; pushbool 2; pushbool 0; return 3")
assert(a == b && a == true && c == false);
a, b, c = T.testC("pushbool 0; pushbool 10; pushnil;\
tobool -3; tobool -3; tobool -3; return 3")
assert(a == 0 && b == 1 && c == 0);
a, b, c = T.testC("gettop; return 2", 10, 20, 30, 40)
assert(a == 40 && b == 5 && !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 && t[(1)] == nil && 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"
});
t = pack(T.testC("rawcall 2,-1; gettop; return .", fn (a, b) {
return 1, 2, 3, 4, a, b
}, "alo", "joao"))
tcheck(t, {
n = 6,
1,
2,
3,
4,
"alo",
"joao"
});
{
local a = {}
for i = 1, 1000 {
a[(i)] = true
}
a[(999)] = 10
local b = T.testC(`call 1 -1; pop 1; tostring -1; return 1`, unpack, a)
assert(b == "10");
}
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(!T.testC("lessthan 2 -3, return 1", "4", "2", "2", "3", "2", "2"));
assert(!T.testC("lessthan -3 2, return 1", "3", "2", "2", "4", "2", "2"));
local b = {
__lt = fn (a, b) {
return a[(1)] < b[(1)]
}
}
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 && b == false);
global fn count(x, n) {
n = n || 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)
}
assert(count(3) == 2);
assert(count('alo') == 1);
assert(count('32') == 2);
assert(count({}) == 1);
assert(count(print) == 2);
assert(count(fn () {
}) == 1);
assert(count(nil) == 1);
assert(count(io.stdin) == 1);
assert(count(nil, 15) == 100);
global fn to(s, x, n) {
n = n || 2
return T.testC(string.format("%s %d; return 1", s, n), x)
}
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) && a != math.deg);
a = T.testC(`
loadstring 2; call 0,1;
pushvalue 3; insert -2; call 1, 1;
call 0, 0;
return 1
`, "x=150", fn (a) {
assert(a == nil);
return 3
})
assert(type(a) == 'string' && x == 150);
global fn check3(p, ...) {
assert(arg.n == 3);
assert(string.find(arg[(3)], p));
}
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"));
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 && 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)
assert(x == print);
T.testC("settable 2", a, "x");
assert(a[(a)] == "x");
b = setmetatable({
p = a
}, {})
getmetatable(b).__index = fn (t, i) {
return t.p[(i)]
}
k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
assert(x == 15 && k == 35);
getmetatable(b).__index = fn (t, i) {
return a[(i)]
}
getmetatable(b).__newindex = fn (t, i, v) {
a[(i)] = v
}
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 && 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);
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
});
{
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 && c == 20 && type(t) == 'table');
a, b = A(`tostring U3; tonumber U4; return 2`)
assert(a == nil && b == 0);
A(`pushnum 100; pushnum 200; replace U2; replace U1`);
b, c = A(`pushvalue U1; pushvalue U2; return 2`)
assert(b == 100 && c == 200);
A(`replace U2; replace U1`, {
x = 1
}, {
x = 2
});
b, c = A(`pushvalue U1; pushvalue U2; return 2`)
assert(b.x == 1 && c.x == 2);
T.checkmemory();
}
local f = T.testC([[ pushnum 10; pushnum 20; pushcclosure 2; return 1]])
assert(T.upvalue(f, 1) == 10 && T.upvalue(f, 2) == 20 && T.upvalue(f, 3) == nil);
T.upvalue(f, 2, "xuxu");
assert(T.upvalue(f, 2) == "xuxu");
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);
local u = T.testC("newuserdata 0; return 1")
assert(debug.getfenv(u) == a);
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);
local i = T.ref({})
T.unref(i);
assert(T.ref({}) == i);
Arr = {}
Lim = 100
for i = 1, Lim {
Arr[(i)] = T.ref({})
}
assert(T.ref(nil) == -1 && T.getref(-1) == nil);
T.unref(-1);
T.unref(-1);
for i = 1, Lim {
T.unref(Arr[(i)]);
}
global fn printlocks() {
local n = T.testC("gettable R; return 1", "n")
print("n", n);
for i = 0, n {
print(i, T.testC("gettable R; return 1", i));
}
}
for i = 1, Lim {
Arr[(i)] = T.ref({})
}
for i = 1, Lim, 2 {
T.unref(Arr[(i)]);
}
assert(type(T.getref(Arr[(2)])) == 'table');
assert(T.getref(-1) == nil);
a = T.ref({})
collectgarbage();
assert(type(T.getref(a)) == 'table');
tt = {}
cl = {
n = 0
}
A = nil
B = nil
local F
F = fn (x) {
local udval = T.udataval(x)
table.insert(cl, udval);
local d = T.newuserdata(100)
d = nil
assert(debug.getmetatable(x).__gc == F);
loadstring("table.insert({}, {})")();
collectgarbage();
assert(debug.getmetatable(x).__gc == F);
local dummy = {}
if A != nil {
assert(type(A) == "userdata");
assert(T.udataval(A) == B);
debug.getmetatable(A);
}
A = x
B = udval
return 1, 2, 3
}
tt.__gc = F
{
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);
x = collectgarbage("count")
collectgarbage("stop");
for i = 1, 1000 {
newproxy(false);
}
assert(collectgarbage("count") > x + 10);
collectgarbage();
assert(collectgarbage("count") <= x + 1);
x = collectgarbage("count")
collectgarbage();
collectgarbage("stop");
a = newproxy(true)
getmetatable(a).__gc = fn () {
}
for i = 1, 1000 {
newproxy(a);
}
assert(collectgarbage("count") >= x + 10);
collectgarbage();
assert(collectgarbage("count") >= x + 10);
collectgarbage();
assert(collectgarbage("count") <= x + 1);
}
collectgarbage("stop");
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)
x = T.newuserdata(4)
y = T.newuserdata(0)
assert(debug.getmetatable(x) == nil && 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 && t[(2)] == b && t[(3)] == c);
t = nil
a = nil
c = nil
T.unref(e);
T.unref(f);
collectgarbage();
assert(table.getn(cl) == 1 && cl[(1)] == nc);
x = T.getref(d)
assert(type(x) == 'userdata' && debug.getmetatable(x) == tt);
x = nil
tt.b = b
tt = nil
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);
assert(cl[(2)] == n5 && cl[(3)] == nb && cl[(4)] == na);
a, na = {}, {}
for i = 30, 1, -1 {
a[(i)] = T.newuserdata(0)
debug.setmetatable(a[(i)], {
__gc = F
});
na[(i)] = T.udataval(a[(i)])
}
cl = {}
a = nil
collectgarbage();
assert(table.getn(cl) == 30);
for i = 1, 30 {
assert(cl[(i)] == na[(i)]);
}
na = nil
for i = 2, Lim, 2 {
T.unref(Arr[(i)]);
}
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();
assert(table.getn(cl) == 0);
for n with pairs(a) {
a[(n)] = nil
}
collectgarbage();
assert(table.getn(cl) == 1 && cl[(1)] == x);
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(!T.testC("equal 2 3; return 1", {}, {}));
assert(!T.testC("equal 2 3; return 1"));
assert(!T.testC("equal 2 3; return 1", 3));
{
local map = {}
local t = {
__eq = fn (a, b) {
return map[(a)] == map[(b)]
}
}
local fn f(x) {
local u = T.newuserdata(0)
debug.setmetatable(u, t);
map[(u)] = x
return u
}
assert(f(10) == f(10));
assert(f(10) != f(11));
assert(T.testC("equal 2 3; return 1", f(10), f(10)));
assert(!T.testC("equal 2 3; return 1", f(10), f(20)));
t.__eq = nil
assert(f(10) != f(10));
}
print('+');
{
local a = {}
for i = 1, 20 {
a[(i)] = T.newuserdata(i)
}
for i = 1, 20, 2 {
debug.setmetatable(a[(i)], {
__gc = fn (x) {
error("error inside gc");
}
});
}
for i = 2, 20, 2 {
debug.setmetatable(a[(i)], {
__gc = fn (x) {
loadstring("A=A+1")();
}
});
}
_G.A = 0
a = 0
while 1 {
if xpcall(collectgarbage, fn (s) {
a = a + 1
}) {
break
}
}
assert(a == 10);
assert(A == 10);
}
{
local a = {}
local lim = 30
for i = 0, lim {
a[(i)] = T.pushuserdata(i)
}
for i = 0, lim {
assert(T.udataval(a[(i)]) == i);
}
for i = 0, lim {
assert(T.pushuserdata(i) == a[(i)]);
}
for i = 0, lim {
a[(a[(i)])] = i
}
for i = 0, lim {
a[(T.pushuserdata(i))] = i
}
assert(type(tostring(a[(1)])) == "string");
}
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' && b == '3');
T.doremote(L1, "_ERRORMESSAGE = nil");
a, b = T.doremote(L1, "return sin(1)")
assert(a == nil && b == 2);
a, b, c = T.doremote(L1, "return a+")
assert(a == nil && b == 3 && type(c) == "string");
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('+');
collectgarbage();
T.totalmem(T.totalmem() + 5000);
assert(!pcall(loadstring("local a={}; for i=1,100000 do a[i]=i end")));
T.totalmem(1000000000);
local fn stack(x) {
if x > 0 {
stack(x - 1);
}
}
global fn testamem(s, f) {
collectgarbage();
stack(10);
local M = T.totalmem()
local oldM = M
local a, b = nil
while 1 {
M = M + 3
T.totalmem(M);
a, b = pcall(f)
if a && b {
break
}
collectgarbage();
if !a && !string.find(b, "memory") {
T.totalmem(1000000000);
error(b, 0);
}
}
T.totalmem(1000000000);
print("\nlimit for " .. s .. ": " .. M - oldM);
return b
}
b = testamem("state creation", T.newstate)
T.closestate(b);
global fn expand(n, s) {
if n == 0 {
return ""
}
local e = string.rep("=", n)
return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n", e, s, expand(n - 1, s), e)
}
G = 0
collectgarbage();
a = collectgarbage("count")
loadstring(expand(20, "G=G+1"))();
assert(G == 20);
collectgarbage();
testamem("thread creation", fn () {
return T.doonnewstack("x=1") == 0
});
testamem("loadstring", fn () {
return loadstring("x=1")
});
local testprog = `
local function foo () return end
local t = {"x"}
a = "aaa"
for _, v in ipairs(t) do a=a..v end
return true
`
_G.a = nil
local t = os.tmpname()
local f = assert(io.open(t, "w"))
f::write(testprog);
f::close();
testamem("dofile", fn () {
local a = loadfile(t)
return a && a()
});
assert(os.remove(t));
assert(_G.a == "aaax");
testamem("string creation", fn () {
local a, b = string.gsub("alo alo", "(a)", fn (x) {
return x .. 'b'
})
return (a == 'ablo ablo')
});
testamem("dump/undump", fn () {
local a = loadstring(testprog)
local b = a && string.dump(a)
a = b && loadstring(b)
return a && a()
});
local t = os.tmpname()
testamem("file creation", fn () {
local f = assert(io.open(t, 'w'))
assert(!io.open("nomenaoexistente"));
io.close(f);
return !loadfile('nomenaoexistente')
});
assert(os.remove(t));
testamem("table creation", fn () {
local a, lim = {}, 10
for i = 1, lim {
a[(i)] = i
a[(i .. 'a')] = {}
}
return (type(a[(lim .. 'a')]) == 'table' && a[(lim)] == lim)
});
local a = 1
close = nil
testamem("closure creation", fn () {
global fn close(b, c) {
return fn (x) {
return a + b + c + x
}
}
return (close(2, 3)(4) == 10)
});
testamem("coroutines", fn () {
local a = coroutine.wrap(fn () {
coroutine.yield(string.rep("a", 10));
return {}
})
assert(string.len(a()) == 10);
return a()
});
print('+');
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');