--- source: src/main.rs expression: compiled input_file: test-data/lua5.2-tests/api.lua --- if T == nil { (Message || print)('\a\n >>> testC not active: skipping API tests <<<\n\a'); return } local debug = require("debug") local pack = table.pack global fn tcheck(t1, t2) { assert(t1.n == (t2.n || #t2) + 1); for i = 2, t1.n { assert(t1[(i)] == t2[(i - 1)]); } } print('testing C API'); a = T.testC("pushvalue R; return 1") assert(a == debug.getregistry()); assert(T.testC("settop 10; absindex -1; return 1") == 10); assert(T.testC("settop 5; absindex -5; return 1") == 1); assert(T.testC("settop 10; absindex 1; return 1") == 1); assert(T.testC("settop 10; absindex R; return 1") < -10); 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); f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2") a, b, c = f() 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 == false && b == true && c == false); 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("copy 3 4; gettop; return .", 2, 3, 4, 5)) tcheck(t, { n = 4, 2, 3, 3, 5 }); t = pack(T.testC("copy -3 -1; gettop; return .", 2, 3, 4, 5)) tcheck(t, { n = 4, 2, 3, 4, 3 }); 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("call 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(`pcall 1 -1; pop 1; tostring -1; return 1`, table.unpack, a) assert(b == "10"); } _G.a = 14 _G.b = "a31" local a = { T.testC([[ getglobal a; getglobal b; getglobal b; setglobal a; gettop; return . ]]) } assert(a[(2)] == 14 && a[(3)] == "a31" && a[(4)] == nil && _G.a == "a31"); assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5); assert(T.testC("pushnum 10; pushnum 20; arith -; return 1") == -10); assert(T.testC("pushnum 10; pushnum -20; arith *; return 1") == -200); assert(T.testC("pushnum 10; pushnum 3; arith ^; return 1") == 1000); assert(T.testC("pushnum 10; pushstring 20; arith /; return 1") == 0.5); assert(T.testC("pushstring 10; pushnum 20; arith -; return 1") == -10); assert(T.testC("pushstring 10; pushstring -20; arith *; return 1") == -200); assert(T.testC("pushstring 10; pushstring 3; arith ^; return 1") == 1000); a, b, c = T.testC(`pushnum 1; pushstring 10; arith _; pushstring 5; return 3`) assert(a == 1 && b == -10 && c == "5"); mt = { __add = fn (a, b) { return setmetatable({ a[(1)] + b[(1)] }, mt) }, __mod = fn (a, b) { return setmetatable({ a[(1)] % b[(1)] }, mt) }, __unm = fn (a) { return setmetatable({ a[(1)] * 2 }, mt) } } a, b, c = setmetatable({ 4 }, mt), setmetatable({ 8 }, mt), setmetatable({ -3 }, mt) x, y, z = T.testC("arith +; return 2", 10, a, b) assert(x == 10 && y[(1)] == 12 && z == nil); assert(T.testC("arith %; return 1", a, c)[(1)] == 4 % -3); assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[(1)] == 8 % (4 + (-3) * 2)); assert(T.testC("compare 2 5 1, return 1", 3, 2, 2, 4, 2, 2)); assert(T.testC("compare 2 5 2, return 1", 3, 2, 2, 4, 2, 2)); assert(!T.testC("compare 3 4 1, return 1", 3, 2, 2, 4, 2, 2)); assert(T.testC("compare 3 4 2, return 1", 3, 2, 2, 4, 2, 2)); assert(T.testC("compare 5 2 1, return 1", 4, 2, 2, 3, 2, 2)); assert(!T.testC("compare 2 -3 1, return 1", "4", "2", "2", "3", "2", "2")); assert(!T.testC("compare -3 2 1, return 1", "3", "2", "2", "4", "2", "2")); assert(!T.testC("compare 1 4 1, return 1")); assert(!T.testC("compare 9 1 2, return 1")); assert(!T.testC("compare 9 9 0, return 1")); 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("compare 2 5 1, return 1", a3, 2, 2, a4, 2, 2)); assert(T.testC("compare 2 5 2, return 1", a3, 2, 2, a4, 2, 2)); assert(T.testC("compare 5 -6 1, return 1", a4, 2, 2, a3, 2, 2)); a, b = T.testC("compare 5 -6 1, return 2", a1, 2, 2, a3, 2, 20) assert(a == 20 && b == false); a, b = T.testC("compare 5 -6 2, return 2", a1, 2, 2, a3, 2, 20) assert(a == 20 && b == false); a, b = T.testC("compare 5 -6 2, return 2", a1, 2, 2, a1, 2, 20) assert(a == 20 && b == true); local t = setmetatable({ x = 20 }, { __len = fn (t) { return t.x } }) a, b, c = T.testC(` len 2; Llen 2; objsize 2; return 3 `, t) assert(a == 20 && b == 20 && c == 0); t.x = "234" t[(1)] = 20 a, b, c = T.testC(` len 2; Llen 2; objsize 2; return 3 `, t) assert(a == "234" && b == 234 && c == 1); t.x = print t[(1)] = 20 a, c = T.testC(` len 2; objsize 2; return 2 `, t) assert(a == print && c == 1); a = setmetatable({ x = "u" }, { __concat = fn (a, b) { return a.x .. '.' .. b.x } }) x, y = T.testC(` pushnum 5 pushvalue 2; pushvalue 2; concat 2; pushvalue -2; return 2; `, a, a) assert(x == a .. a && y == 5); assert(T.testC("concat 0; return 1") == ""); assert(T.testC("concat 1; return 1", "xuxu") == "xuxu"); global fn B(x) { return x && 1 || 0 } 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 B(a) + B(b) + B(c) + B(d) + B(e) + B(f) + B(g) + (100 * B(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", { 1, 2, 3 }) == 3); assert(to("objsize", "alo\0\0a") == 6); assert(to("objsize", T.newuserdata(0)) == 0); assert(to("objsize", T.newuserdata(101)) == 101); assert(to("objsize", 124) == 0); assert(to("objsize", true) == 0); assert(to("tonumber", {}) == 0); assert(to("tonumber", "12") == 12); assert(to("tonumber", "s2") == 0); assert(to("tonumber", 1, 20) == 0); assert(to("topointer", 10) == 0); assert(to("topointer", true) == 0); assert(to("topointer", T.pushuserdata(20)) == 20); assert(to("topointer", io.read) != 0); assert(to("func2num", 20) == 0); assert(to("func2num", T.pushuserdata(10)) == 0); assert(to("func2num", io.read) != 0); a = to("tocfunction", math.deg) assert(a(3) == math.deg(3) && a == math.deg); { collectgarbage("stop"); local s, msg = pcall(T.testC, "checkstack 1000023 XXXX") assert(!s && string.find(msg, "XXXX")); s = string.rep("pushnil;checkstack 1 XX;", 1000000) s, msg = pcall(T.testC, s) assert(!s && string.find(msg, "XX")); collectgarbage("restart"); } local prog = { "checkstack 30000 msg", "newtable" } for i = 1, 12000 { prog[(#prog + 1)] = "pushnum " .. i prog[(#prog + 1)] = "pushnum " .. i * 10 } prog[(#prog + 1)] = "rawgeti R 2" prog[(#prog + 1)] = "insert " .. -(2 * 12000 + 2) for i = 1, 12000 { prog[(#prog + 1)] = "settable " .. -(2 * (12000 - i + 1) + 1) } prog[(#prog + 1)] = "return 2" prog = table.concat(prog, ";") local g, t = T.testC(prog) assert(g == _G); for i = 1, 12000 { assert(t[(i)] == i * 10); t[(i)] = nil } assert(next(t) == nil); prog, g, t = nil a = T.testC(` loadstring 2; pcall 0,1; pushvalue 3; insert -2; pcall 1, 1; pcall 0, 0; return 1 `, "x=150", fn (a) { assert(a == nil); return 3 }) assert(type(a) == 'string' && x == 150); global fn check3(p, ...) { local arg = { ... } assert(#arg == 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")); global fn checkerrnopro(code, msg) { L = coroutine.create(fn () { }) local stt, err = pcall(T.testC, code) assert(!stt && string.find(err, msg)); } checkerrnopro("pushnum 3; call 0 0", "attempt to call"); global fn f() { f(); } checkerrnopro("getglobal 'f'; call 0 0;", "stack overflow"); 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(); } assert(T.testC([[isnull U1; return 1]]) == true); assert(T.testC([[isnull U100; return 1]]) == true); assert(T.testC([[pushvalue U1; return 1]]) == nil); 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"); { local A = "checkstack 300 msg;" .. string.rep("pushnum 10;", 255) .. "pushcclosure 255; return 1" A = T.testC(A) for i = 1, 255 { assert(A(("pushvalue U%d; return 1")::format(i)) == 10); } assert(A("isnull U256; return 1")); assert(!A("isnil U256; return 1")); } assert(!pcall(debug.setuservalue, 3, {})); assert(!pcall(debug.setuservalue, nil, {})); assert(!pcall(debug.setuservalue, T.pushuserdata(1), {})); local b = T.newuserdata(0) local a = {} assert(debug.getuservalue(b) == nil); assert(debug.setuservalue(b, a)); assert(debug.getuservalue(b) == a); assert(debug.setuservalue(b, nil)); assert(debug.getuservalue(b) == nil); assert(debug.getuservalue(4) == nil); 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 f = T.makeCfunc("gettable R; return 1") local n = f("n") print("n", n); for i = 0, n { print(i, f(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); assert(load("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 { T.newuserdata(0); } assert(collectgarbage("count") > x + 10); collectgarbage(); assert(collectgarbage("count") <= x + 1); x = collectgarbage("count") collectgarbage(); collectgarbage("stop"); a = { __gc = fn () { } } for i = 1, 1000 { debug.setmetatable(T.newuserdata(0), a); } assert(collectgarbage("count") >= x + 10); collectgarbage(); assert(collectgarbage("count") >= x + 10); collectgarbage(); assert(collectgarbage("count") <= x + 1); collectgarbage("restart"); } 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(!pcall(io.input, a)); assert(!pcall(io.input, x)); 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(#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(#cl == 4); assert(cl[(2)] == n5 && cl[(3)] == nb && cl[(4)] == na); collectgarbage("restart"); 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(#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(#cl == 0); for n with pairs(a) { a[(n)] = nil } collectgarbage(); assert(#cl == 1 && cl[(1)] == x); assert(T.testC("compare 2 4 0; return 1", print, 1, print, 20)); assert(T.testC("compare 3 2 0; return 1", 'alo', "alo")); assert(T.testC("compare 2 3 0; return 1", nil, nil)); assert(!T.testC("compare 2 3 0; return 1", {}, {})); assert(!T.testC("compare 2 3 0; return 1")); assert(!T.testC("compare 2 3 0; 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("compare 2 3 0; return 1", f(10), f(10))); assert(!T.testC("compare 2 3 0; return 1", f(10), f(20))); t.__eq = nil assert(f(10) != f(10)); } print('+'); _G.t = {} T.sethook(` # set a line hook after 3 count hooks sethook 4 0 ' getglobal t; pushvalue -3; append -2 pushvalue -2; append -2 '`, "c", 3); local a = 1 a = 1 a = 1 a = 1 a = 1 debug.sethook(); t = _G.t assert(t[(1)] == "line"); line = t[(2)] assert(t[(3)] == "line" && t[(4)] == line + 1); assert(t[(5)] == "line" && t[(6)] == line + 2); assert(t[(7)] == nil); { 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) { load("A=A+1")(); } }); } _G.A = 0 a = 0 while 1 { local stat, msg = pcall(collectgarbage) if stat { break } else { a = a + 1 assert(string.find(msg, "__gc")); } } 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(T.doremote(L1, "X='a'; return 'a'") == 'a'); assert(#pack(T.doremote(L1, "function f () return 'alo', 3 end; f()")) == 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 && c == 3 && type(b) == "string"); T.loadlib(L1); a, b, c = T.doremote(L1, ` string = require'string' a = require'_G'; assert(a == _G and require("_G") == a) io = require'io'; assert(type(io.read) == "function") assert(require("io") == io) a = require'table'; assert(type(a.insert) == "function") a = require'debug'; assert(type(a.getlocal) == "function") a = require'math'; 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, `getglobal "a"; pushstring "x"; pushnum 1; settable -3`); assert(T.doremote(L1, "return a.x") == "1"); T.closestate(L1); L1 = nil print('+'); assert(!pcall(T.newuserdata, 2 ^ 32 - 4)); collectgarbage(); T.totalmem(T.totalmem() + 5000); assert(!pcall(load("local a={}; for i=1,100000 do a[i]=i end"))); T.totalmem(1000000000); global fn testamem(s, f) { collectgarbage(); collectgarbage(); local M = T.totalmem() local oldM = M local a, b = nil while 1 { M = M + 7 T.totalmem(M); a, b = pcall(f) T.totalmem(1000000000); if a && b { break } collectgarbage(); if !a && !(string.find(b, "memory") || string.find(b, "overflow")) { error(b, 0); } } print("\nlimit for " .. s .. ": " .. M - oldM); return b } b = testamem("state creation", T.newstate) T.closestate(b); mt = T.testC("rawgeti R 1; return 1") assert(type(mt) == "thread" && coroutine.running() == mt); 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") load(expand(20, "G=G+1"))(); assert(G == 20); collectgarbage(); testamem("thread creation", fn () { return T.doonnewstack("x=1") == 0 }); testamem("loadstring", fn () { return load("x=1") }); local testprog = ` local function foo () return end local t = {"x"} a = "aaa" for i = 1, #t do a=a..t[i] 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 = load(testprog) local b = a && string.dump(a) a = b && load(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) }); testamem("constructors", fn () { local a = { 10, 20, 30, 40, 50, a = 1, b = 2, c = 3, d = 4, e = 5 } return (type(a) == 'table' && a.e == 5) }); 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('+'); local fn gsub(a, b, c) { a, b = T.testC("gsub 2 3 4; gettop; return 2", a, b, c) assert(b == 5); return a } assert(gsub("alo.alo.uhuh.", ".", "//") == "alo//alo//uhuh//"); assert(gsub("alo.alo.uhuh.", "alo", "//") == "//.//.uhuh."); assert(gsub("", "alo", "//") == ""); assert(gsub("...", ".", "/.") == "/././."); assert(gsub("...", "...", "") == ""); local mt_xuxu, res, top = T.testC("newmetatable xuxu; gettop; return 3") assert(type(mt_xuxu) == "table" && res && top == 3); local d, res, top = T.testC("newmetatable xuxu; gettop; return 3") assert(mt_xuxu == d && !res && top == 3); d, res, top = T.testC("newmetatable xuxu1; gettop; return 3") assert(mt_xuxu != d && res && top == 3); x = T.newuserdata(0) y = T.newuserdata(0) T.testC("pushstring xuxu; gettable R; setmetatable 2", x); assert(getmetatable(x) == mt_xuxu); local res1, res2, top = T.testC(`testudata -1 xuxu testudata 2 xuxu gettop return 3`, x) assert(res1 && res2 && top == 4); res1, res2, top = T.testC(`testudata -1 xuxu1 testudata 2 xuxu1 gettop return 3`, x) assert(!res1 && !res2 && top == 4); res1, res2, top = T.testC(`testudata -1 xuxu2 testudata 2 xuxu2 gettop return 3`, x) assert(!res1 && !res2 && top == 4); res1, res2, top = T.testC(`testudata -1 xuxu testudata 2 xuxu gettop return 3`, y) assert(!res1 && !res2 && top == 4); { local r = debug.getregistry() assert(r.xuxu == mt_xuxu && r.xuxu1 == d); r.xuxu = nil r.xuxu1 = nil } print('OK');