diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-12-17 14:46:37 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-12-17 14:46:37 -0200 |
commit | 063d4e4543088e7a21965bda8ee5a0f952a9029e (patch) | |
tree | 6c3f2f8e98c26f071a94a32f9f2754396a66a9de /testes/api.lua | |
parent | e354c6355e7f48e087678ec49e340ca0696725b1 (diff) | |
download | lua-5.3.5.tar.gz lua-5.3.5.tar.bz2 lua-5.3.5.zip |
Lua 5.3.5 ported to gitv5.3.5
This is the first commit for the branch Lua 5.3. All source files
were copied from the official distribution of 5.3.5 in the Lua site.
The test files are the same of 5.3.4. The manual came from the
previous RCS repository, revision 1.167.1.2.
Diffstat (limited to 'testes/api.lua')
-rw-r--r-- | testes/api.lua | 1172 |
1 files changed, 1172 insertions, 0 deletions
diff --git a/testes/api.lua b/testes/api.lua new file mode 100644 index 00000000..c27ee97f --- /dev/null +++ b/testes/api.lua | |||
@@ -0,0 +1,1172 @@ | |||
1 | -- $Id: api.lua,v 1.147 2016/11/07 13:06:25 roberto Exp $ | ||
2 | -- See Copyright Notice in file all.lua | ||
3 | |||
4 | if T==nil then | ||
5 | (Message or print)('\n >>> testC not active: skipping API tests <<<\n') | ||
6 | return | ||
7 | end | ||
8 | |||
9 | local debug = require "debug" | ||
10 | |||
11 | local pack = table.pack | ||
12 | |||
13 | |||
14 | function tcheck (t1, t2) | ||
15 | assert(t1.n == (t2.n or #t2) + 1) | ||
16 | for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end | ||
17 | end | ||
18 | |||
19 | |||
20 | local function checkerr (msg, f, ...) | ||
21 | local stat, err = pcall(f, ...) | ||
22 | assert(not stat and string.find(err, msg)) | ||
23 | end | ||
24 | |||
25 | |||
26 | print('testing C API') | ||
27 | |||
28 | a = T.testC("pushvalue R; return 1") | ||
29 | assert(a == debug.getregistry()) | ||
30 | |||
31 | |||
32 | -- absindex | ||
33 | assert(T.testC("settop 10; absindex -1; return 1") == 10) | ||
34 | assert(T.testC("settop 5; absindex -5; return 1") == 1) | ||
35 | assert(T.testC("settop 10; absindex 1; return 1") == 1) | ||
36 | assert(T.testC("settop 10; absindex R; return 1") < -10) | ||
37 | |||
38 | -- testing alignment | ||
39 | a = T.d2s(12458954321123.0) | ||
40 | assert(a == string.pack("d", 12458954321123.0)) | ||
41 | assert(T.s2d(a) == 12458954321123.0) | ||
42 | |||
43 | a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2") | ||
44 | assert(a == 2 and b == 3 and not c) | ||
45 | |||
46 | f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2") | ||
47 | a,b,c = f() | ||
48 | assert(a == 2 and b == 3 and not c) | ||
49 | |||
50 | -- test that all trues are equal | ||
51 | a,b,c = T.testC("pushbool 1; pushbool 2; pushbool 0; return 3") | ||
52 | assert(a == b and a == true and c == false) | ||
53 | a,b,c = T.testC"pushbool 0; pushbool 10; pushnil;\ | ||
54 | tobool -3; tobool -3; tobool -3; return 3" | ||
55 | assert(a==false and b==true and c==false) | ||
56 | |||
57 | |||
58 | a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40) | ||
59 | assert(a == 40 and b == 5 and not c) | ||
60 | |||
61 | t = pack(T.testC("settop 5; return *", 2, 3)) | ||
62 | tcheck(t, {n=4,2,3}) | ||
63 | |||
64 | t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23)) | ||
65 | assert(t.n == 10 and t[1] == nil and t[10] == nil) | ||
66 | |||
67 | t = pack(T.testC("remove -2; return *", 2, 3, 4)) | ||
68 | tcheck(t, {n=2,2,4}) | ||
69 | |||
70 | t = pack(T.testC("insert -1; return *", 2, 3)) | ||
71 | tcheck(t, {n=2,2,3}) | ||
72 | |||
73 | t = pack(T.testC("insert 3; return *", 2, 3, 4, 5)) | ||
74 | tcheck(t, {n=4,2,5,3,4}) | ||
75 | |||
76 | t = pack(T.testC("replace 2; return *", 2, 3, 4, 5)) | ||
77 | tcheck(t, {n=3,5,3,4}) | ||
78 | |||
79 | t = pack(T.testC("replace -2; return *", 2, 3, 4, 5)) | ||
80 | tcheck(t, {n=3,2,3,5}) | ||
81 | |||
82 | t = pack(T.testC("remove 3; return *", 2, 3, 4, 5)) | ||
83 | tcheck(t, {n=3,2,4,5}) | ||
84 | |||
85 | t = pack(T.testC("copy 3 4; return *", 2, 3, 4, 5)) | ||
86 | tcheck(t, {n=4,2,3,3,5}) | ||
87 | |||
88 | t = pack(T.testC("copy -3 -1; return *", 2, 3, 4, 5)) | ||
89 | tcheck(t, {n=4,2,3,4,3}) | ||
90 | |||
91 | do -- testing 'rotate' | ||
92 | local t = {10, 20, 30, 40, 50, 60} | ||
93 | for i = -6, 6 do | ||
94 | local s = string.format("rotate 2 %d; return 7", i) | ||
95 | local t1 = pack(T.testC(s, 10, 20, 30, 40, 50, 60)) | ||
96 | tcheck(t1, t) | ||
97 | table.insert(t, 1, table.remove(t)) | ||
98 | end | ||
99 | |||
100 | t = pack(T.testC("rotate -2 1; return *", 10, 20, 30, 40)) | ||
101 | tcheck(t, {10, 20, 40, 30}) | ||
102 | t = pack(T.testC("rotate -2 -1; return *", 10, 20, 30, 40)) | ||
103 | tcheck(t, {10, 20, 40, 30}) | ||
104 | |||
105 | -- some corner cases | ||
106 | t = pack(T.testC("rotate -1 0; return *", 10, 20, 30, 40)) | ||
107 | tcheck(t, {10, 20, 30, 40}) | ||
108 | t = pack(T.testC("rotate -1 1; return *", 10, 20, 30, 40)) | ||
109 | tcheck(t, {10, 20, 30, 40}) | ||
110 | t = pack(T.testC("rotate 5 -1; return *", 10, 20, 30, 40)) | ||
111 | tcheck(t, {10, 20, 30, 40}) | ||
112 | end | ||
113 | |||
114 | -- testing non-function message handlers | ||
115 | do | ||
116 | local f = T.makeCfunc[[ | ||
117 | getglobal error | ||
118 | pushstring bola | ||
119 | pcall 1 1 1 # call 'error' with given handler | ||
120 | pushstatus | ||
121 | return 2 # return error message and status | ||
122 | ]] | ||
123 | |||
124 | local msg, st = f({}) -- invalid handler | ||
125 | assert(st == "ERRERR" and string.find(msg, "error handling")) | ||
126 | local msg, st = f(nil) -- invalid handler | ||
127 | assert(st == "ERRERR" and string.find(msg, "error handling")) | ||
128 | |||
129 | local a = setmetatable({}, {__call = function (_, x) return x:upper() end}) | ||
130 | local msg, st = f(a) -- callable handler | ||
131 | assert(st == "ERRRUN" and msg == "BOLA") | ||
132 | end | ||
133 | |||
134 | t = pack(T.testC("insert 3; pushvalue 3; remove 3; pushvalue 2; remove 2; \ | ||
135 | insert 2; pushvalue 1; remove 1; insert 1; \ | ||
136 | insert -2; pushvalue -2; remove -3; return *", | ||
137 | 2, 3, 4, 5, 10, 40, 90)) | ||
138 | tcheck(t, {n=7,2,3,4,5,10,40,90}) | ||
139 | |||
140 | t = pack(T.testC("concat 5; return *", "alo", 2, 3, "joao", 12)) | ||
141 | tcheck(t, {n=1,"alo23joao12"}) | ||
142 | |||
143 | -- testing MULTRET | ||
144 | t = pack(T.testC("call 2,-1; return *", | ||
145 | function (a,b) return 1,2,3,4,a,b end, "alo", "joao")) | ||
146 | tcheck(t, {n=6,1,2,3,4,"alo", "joao"}) | ||
147 | |||
148 | do -- test returning more results than fit in the caller stack | ||
149 | local a = {} | ||
150 | for i=1,1000 do a[i] = true end; a[999] = 10 | ||
151 | local b = T.testC([[pcall 1 -1 0; pop 1; tostring -1; return 1]], | ||
152 | table.unpack, a) | ||
153 | assert(b == "10") | ||
154 | end | ||
155 | |||
156 | |||
157 | -- testing globals | ||
158 | _G.a = 14; _G.b = "a31" | ||
159 | local a = {T.testC[[ | ||
160 | getglobal a; | ||
161 | getglobal b; | ||
162 | getglobal b; | ||
163 | setglobal a; | ||
164 | return * | ||
165 | ]]} | ||
166 | assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.a == "a31") | ||
167 | |||
168 | |||
169 | -- testing arith | ||
170 | assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5) | ||
171 | assert(T.testC("pushnum 10; pushnum 20; arith -; return 1") == -10) | ||
172 | assert(T.testC("pushnum 10; pushnum -20; arith *; return 1") == -200) | ||
173 | assert(T.testC("pushnum 10; pushnum 3; arith ^; return 1") == 1000) | ||
174 | assert(T.testC("pushnum 10; pushstring 20; arith /; return 1") == 0.5) | ||
175 | assert(T.testC("pushstring 10; pushnum 20; arith -; return 1") == -10) | ||
176 | assert(T.testC("pushstring 10; pushstring -20; arith *; return 1") == -200) | ||
177 | assert(T.testC("pushstring 10; pushstring 3; arith ^; return 1") == 1000) | ||
178 | assert(T.testC("arith /; return 1", 2, 0) == 10.0/0) | ||
179 | a = T.testC("pushnum 10; pushint 3; arith \\; return 1") | ||
180 | assert(a == 3.0 and math.type(a) == "float") | ||
181 | a = T.testC("pushint 10; pushint 3; arith \\; return 1") | ||
182 | assert(a == 3 and math.type(a) == "integer") | ||
183 | a = assert(T.testC("pushint 10; pushint 3; arith +; return 1")) | ||
184 | assert(a == 13 and math.type(a) == "integer") | ||
185 | a = assert(T.testC("pushnum 10; pushint 3; arith +; return 1")) | ||
186 | assert(a == 13 and math.type(a) == "float") | ||
187 | a,b,c = T.testC([[pushnum 1; | ||
188 | pushstring 10; arith _; | ||
189 | pushstring 5; return 3]]) | ||
190 | assert(a == 1 and b == -10 and c == "5") | ||
191 | mt = {__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end, | ||
192 | __mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end, | ||
193 | __unm = function (a) return setmetatable({a[1]* 2}, mt) end} | ||
194 | a,b,c = setmetatable({4}, mt), | ||
195 | setmetatable({8}, mt), | ||
196 | setmetatable({-3}, mt) | ||
197 | x,y,z = T.testC("arith +; return 2", 10, a, b) | ||
198 | assert(x == 10 and y[1] == 12 and z == nil) | ||
199 | assert(T.testC("arith %; return 1", a, c)[1] == 4%-3) | ||
200 | assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] == | ||
201 | 8 % (4 + (-3)*2)) | ||
202 | |||
203 | -- errors in arithmetic | ||
204 | checkerr("divide by zero", T.testC, "arith \\", 10, 0) | ||
205 | checkerr("%%0", T.testC, "arith %", 10, 0) | ||
206 | |||
207 | |||
208 | -- testing lessthan and lessequal | ||
209 | assert(T.testC("compare LT 2 5, return 1", 3, 2, 2, 4, 2, 2)) | ||
210 | assert(T.testC("compare LE 2 5, return 1", 3, 2, 2, 4, 2, 2)) | ||
211 | assert(not T.testC("compare LT 3 4, return 1", 3, 2, 2, 4, 2, 2)) | ||
212 | assert(T.testC("compare LE 3 4, return 1", 3, 2, 2, 4, 2, 2)) | ||
213 | assert(T.testC("compare LT 5 2, return 1", 4, 2, 2, 3, 2, 2)) | ||
214 | assert(not T.testC("compare LT 2 -3, return 1", "4", "2", "2", "3", "2", "2")) | ||
215 | assert(not T.testC("compare LT -3 2, return 1", "3", "2", "2", "4", "2", "2")) | ||
216 | |||
217 | -- non-valid indices produce false | ||
218 | assert(not T.testC("compare LT 1 4, return 1")) | ||
219 | assert(not T.testC("compare LE 9 1, return 1")) | ||
220 | assert(not T.testC("compare EQ 9 9, return 1")) | ||
221 | |||
222 | local b = {__lt = function (a,b) return a[1] < b[1] end} | ||
223 | local a1,a3,a4 = setmetatable({1}, b), | ||
224 | setmetatable({3}, b), | ||
225 | setmetatable({4}, b) | ||
226 | assert(T.testC("compare LT 2 5, return 1", a3, 2, 2, a4, 2, 2)) | ||
227 | assert(T.testC("compare LE 2 5, return 1", a3, 2, 2, a4, 2, 2)) | ||
228 | assert(T.testC("compare LT 5 -6, return 1", a4, 2, 2, a3, 2, 2)) | ||
229 | a,b = T.testC("compare LT 5 -6, return 2", a1, 2, 2, a3, 2, 20) | ||
230 | assert(a == 20 and b == false) | ||
231 | a,b = T.testC("compare LE 5 -6, return 2", a1, 2, 2, a3, 2, 20) | ||
232 | assert(a == 20 and b == false) | ||
233 | a,b = T.testC("compare LE 5 -6, return 2", a1, 2, 2, a1, 2, 20) | ||
234 | assert(a == 20 and b == true) | ||
235 | |||
236 | -- testing length | ||
237 | local t = setmetatable({x = 20}, {__len = function (t) return t.x end}) | ||
238 | a,b,c = T.testC([[ | ||
239 | len 2; | ||
240 | Llen 2; | ||
241 | objsize 2; | ||
242 | return 3 | ||
243 | ]], t) | ||
244 | assert(a == 20 and b == 20 and c == 0) | ||
245 | |||
246 | t.x = "234"; t[1] = 20 | ||
247 | a,b,c = T.testC([[ | ||
248 | len 2; | ||
249 | Llen 2; | ||
250 | objsize 2; | ||
251 | return 3 | ||
252 | ]], t) | ||
253 | assert(a == "234" and b == 234 and c == 1) | ||
254 | |||
255 | t.x = print; t[1] = 20 | ||
256 | a,c = T.testC([[ | ||
257 | len 2; | ||
258 | objsize 2; | ||
259 | return 2 | ||
260 | ]], t) | ||
261 | assert(a == print and c == 1) | ||
262 | |||
263 | |||
264 | -- testing __concat | ||
265 | |||
266 | a = setmetatable({x="u"}, {__concat = function (a,b) return a.x..'.'..b.x end}) | ||
267 | x,y = T.testC([[ | ||
268 | pushnum 5 | ||
269 | pushvalue 2; | ||
270 | pushvalue 2; | ||
271 | concat 2; | ||
272 | pushvalue -2; | ||
273 | return 2; | ||
274 | ]], a, a) | ||
275 | assert(x == a..a and y == 5) | ||
276 | |||
277 | -- concat with 0 elements | ||
278 | assert(T.testC("concat 0; return 1") == "") | ||
279 | |||
280 | -- concat with 1 element | ||
281 | assert(T.testC("concat 1; return 1", "xuxu") == "xuxu") | ||
282 | |||
283 | |||
284 | |||
285 | -- testing lua_is | ||
286 | |||
287 | function B(x) return x and 1 or 0 end | ||
288 | |||
289 | function count (x, n) | ||
290 | n = n or 2 | ||
291 | local prog = [[ | ||
292 | isnumber %d; | ||
293 | isstring %d; | ||
294 | isfunction %d; | ||
295 | iscfunction %d; | ||
296 | istable %d; | ||
297 | isuserdata %d; | ||
298 | isnil %d; | ||
299 | isnull %d; | ||
300 | return 8 | ||
301 | ]] | ||
302 | prog = string.format(prog, n, n, n, n, n, n, n, n) | ||
303 | local a,b,c,d,e,f,g,h = T.testC(prog, x) | ||
304 | return B(a)+B(b)+B(c)+B(d)+B(e)+B(f)+B(g)+(100*B(h)) | ||
305 | end | ||
306 | |||
307 | assert(count(3) == 2) | ||
308 | assert(count('alo') == 1) | ||
309 | assert(count('32') == 2) | ||
310 | assert(count({}) == 1) | ||
311 | assert(count(print) == 2) | ||
312 | assert(count(function () end) == 1) | ||
313 | assert(count(nil) == 1) | ||
314 | assert(count(io.stdin) == 1) | ||
315 | assert(count(nil, 15) == 100) | ||
316 | |||
317 | |||
318 | -- testing lua_to... | ||
319 | |||
320 | function to (s, x, n) | ||
321 | n = n or 2 | ||
322 | return T.testC(string.format("%s %d; return 1", s, n), x) | ||
323 | end | ||
324 | |||
325 | local hfunc = string.gmatch("", "") -- a "heavy C function" (with upvalues) | ||
326 | assert(debug.getupvalue(hfunc, 1)) | ||
327 | assert(to("tostring", {}) == nil) | ||
328 | assert(to("tostring", "alo") == "alo") | ||
329 | assert(to("tostring", 12) == "12") | ||
330 | assert(to("tostring", 12, 3) == nil) | ||
331 | assert(to("objsize", {}) == 0) | ||
332 | assert(to("objsize", {1,2,3}) == 3) | ||
333 | assert(to("objsize", "alo\0\0a") == 6) | ||
334 | assert(to("objsize", T.newuserdata(0)) == 0) | ||
335 | assert(to("objsize", T.newuserdata(101)) == 101) | ||
336 | assert(to("objsize", 124) == 0) | ||
337 | assert(to("objsize", true) == 0) | ||
338 | assert(to("tonumber", {}) == 0) | ||
339 | assert(to("tonumber", "12") == 12) | ||
340 | assert(to("tonumber", "s2") == 0) | ||
341 | assert(to("tonumber", 1, 20) == 0) | ||
342 | assert(to("topointer", 10) == 0) | ||
343 | assert(to("topointer", true) == 0) | ||
344 | assert(to("topointer", T.pushuserdata(20)) == 20) | ||
345 | assert(to("topointer", io.read) ~= 0) -- light C function | ||
346 | assert(to("topointer", hfunc) ~= 0) -- "heavy" C function | ||
347 | assert(to("topointer", function () end) ~= 0) -- Lua function | ||
348 | assert(to("topointer", io.stdin) ~= 0) -- full userdata | ||
349 | assert(to("func2num", 20) == 0) | ||
350 | assert(to("func2num", T.pushuserdata(10)) == 0) | ||
351 | assert(to("func2num", io.read) ~= 0) -- light C function | ||
352 | assert(to("func2num", hfunc) ~= 0) -- "heavy" C function (with upvalue) | ||
353 | a = to("tocfunction", math.deg) | ||
354 | assert(a(3) == math.deg(3) and a == math.deg) | ||
355 | |||
356 | |||
357 | print("testing panic function") | ||
358 | do | ||
359 | -- trivial error | ||
360 | assert(T.checkpanic("pushstring hi; error") == "hi") | ||
361 | |||
362 | -- using the stack inside panic | ||
363 | assert(T.checkpanic("pushstring hi; error;", | ||
364 | [[checkstack 5 XX | ||
365 | pushstring ' alo' | ||
366 | pushstring ' mundo' | ||
367 | concat 3]]) == "hi alo mundo") | ||
368 | |||
369 | -- "argerror" without frames | ||
370 | assert(T.checkpanic("loadstring 4") == | ||
371 | "bad argument #4 (string expected, got no value)") | ||
372 | |||
373 | |||
374 | -- memory error | ||
375 | T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k) | ||
376 | assert(T.checkpanic("newuserdata 20000") == "not enough memory") | ||
377 | T.totalmem(0) -- restore high limit | ||
378 | |||
379 | -- stack error | ||
380 | if not _soft then | ||
381 | local msg = T.checkpanic[[ | ||
382 | pushstring "function f() f() end" | ||
383 | loadstring -1; call 0 0 | ||
384 | getglobal f; call 0 0 | ||
385 | ]] | ||
386 | assert(string.find(msg, "stack overflow")) | ||
387 | end | ||
388 | |||
389 | end | ||
390 | |||
391 | -- testing deep C stack | ||
392 | if not _soft then | ||
393 | print("testing stack overflow") | ||
394 | collectgarbage("stop") | ||
395 | checkerr("XXXX", T.testC, "checkstack 1000023 XXXX") -- too deep | ||
396 | -- too deep (with no message) | ||
397 | checkerr("^stack overflow$", T.testC, "checkstack 1000023 ''") | ||
398 | local s = string.rep("pushnil;checkstack 1 XX;", 1000000) | ||
399 | checkerr("overflow", T.testC, s) | ||
400 | collectgarbage("restart") | ||
401 | print'+' | ||
402 | end | ||
403 | |||
404 | local lim = _soft and 500 or 12000 | ||
405 | local prog = {"checkstack " .. (lim * 2 + 100) .. "msg", "newtable"} | ||
406 | for i = 1,lim do | ||
407 | prog[#prog + 1] = "pushnum " .. i | ||
408 | prog[#prog + 1] = "pushnum " .. i * 10 | ||
409 | end | ||
410 | |||
411 | prog[#prog + 1] = "rawgeti R 2" -- get global table in registry | ||
412 | prog[#prog + 1] = "insert " .. -(2*lim + 2) | ||
413 | |||
414 | for i = 1,lim do | ||
415 | prog[#prog + 1] = "settable " .. -(2*(lim - i + 1) + 1) | ||
416 | end | ||
417 | |||
418 | prog[#prog + 1] = "return 2" | ||
419 | |||
420 | prog = table.concat(prog, ";") | ||
421 | local g, t = T.testC(prog) | ||
422 | assert(g == _G) | ||
423 | for i = 1,lim do assert(t[i] == i*10); t[i] = nil end | ||
424 | assert(next(t) == nil) | ||
425 | prog, g, t = nil | ||
426 | |||
427 | -- testing errors | ||
428 | |||
429 | a = T.testC([[ | ||
430 | loadstring 2; pcall 0 1 0; | ||
431 | pushvalue 3; insert -2; pcall 1 1 0; | ||
432 | pcall 0 0 0; | ||
433 | return 1 | ||
434 | ]], "x=150", function (a) assert(a==nil); return 3 end) | ||
435 | |||
436 | assert(type(a) == 'string' and x == 150) | ||
437 | |||
438 | function check3(p, ...) | ||
439 | local arg = {...} | ||
440 | assert(#arg == 3) | ||
441 | assert(string.find(arg[3], p)) | ||
442 | end | ||
443 | check3(":1:", T.testC("loadstring 2; return *", "x=")) | ||
444 | check3("%.", T.testC("loadfile 2; return *", ".")) | ||
445 | check3("xxxx", T.testC("loadfile 2; return *", "xxxx")) | ||
446 | |||
447 | -- test errors in non protected threads | ||
448 | function checkerrnopro (code, msg) | ||
449 | local th = coroutine.create(function () end) -- create new thread | ||
450 | local stt, err = pcall(T.testC, th, code) -- run code there | ||
451 | assert(not stt and string.find(err, msg)) | ||
452 | end | ||
453 | |||
454 | if not _soft then | ||
455 | checkerrnopro("pushnum 3; call 0 0", "attempt to call") | ||
456 | print"testing stack overflow in unprotected thread" | ||
457 | function f () f() end | ||
458 | checkerrnopro("getglobal 'f'; call 0 0;", "stack overflow") | ||
459 | end | ||
460 | print"+" | ||
461 | |||
462 | |||
463 | -- testing table access | ||
464 | |||
465 | do -- getp/setp | ||
466 | local a = {} | ||
467 | T.testC("rawsetp 2 1", a, 20) | ||
468 | assert(a[T.pushuserdata(1)] == 20) | ||
469 | assert(T.testC("rawgetp 2 1; return 1", a) == 20) | ||
470 | end | ||
471 | |||
472 | a = {x=0, y=12} | ||
473 | x, y = T.testC("gettable 2; pushvalue 4; gettable 2; return 2", | ||
474 | a, 3, "y", 4, "x") | ||
475 | assert(x == 0 and y == 12) | ||
476 | T.testC("settable -5", a, 3, 4, "x", 15) | ||
477 | assert(a.x == 15) | ||
478 | a[a] = print | ||
479 | x = T.testC("gettable 2; return 1", a) -- table and key are the same object! | ||
480 | assert(x == print) | ||
481 | T.testC("settable 2", a, "x") -- table and key are the same object! | ||
482 | assert(a[a] == "x") | ||
483 | |||
484 | b = setmetatable({p = a}, {}) | ||
485 | getmetatable(b).__index = function (t, i) return t.p[i] end | ||
486 | k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x") | ||
487 | assert(x == 15 and k == 35) | ||
488 | k = T.testC("getfield 2 y, return 1", b) | ||
489 | assert(k == 12) | ||
490 | getmetatable(b).__index = function (t, i) return a[i] end | ||
491 | getmetatable(b).__newindex = function (t, i,v ) a[i] = v end | ||
492 | y = T.testC("insert 2; gettable -5; return 1", 2, 3, 4, "y", b) | ||
493 | assert(y == 12) | ||
494 | k = T.testC("settable -5, return 1", b, 3, 4, "x", 16) | ||
495 | assert(a.x == 16 and k == 4) | ||
496 | a[b] = 'xuxu' | ||
497 | y = T.testC("gettable 2, return 1", b) | ||
498 | assert(y == 'xuxu') | ||
499 | T.testC("settable 2", b, 19) | ||
500 | assert(a[b] == 19) | ||
501 | |||
502 | -- | ||
503 | do -- testing getfield/setfield with long keys | ||
504 | local t = {_012345678901234567890123456789012345678901234567890123456789 = 32} | ||
505 | local a = T.testC([[ | ||
506 | getfield 2 _012345678901234567890123456789012345678901234567890123456789 | ||
507 | return 1 | ||
508 | ]], t) | ||
509 | assert(a == 32) | ||
510 | local a = T.testC([[ | ||
511 | pushnum 33 | ||
512 | setglobal _012345678901234567890123456789012345678901234567890123456789 | ||
513 | ]]) | ||
514 | assert(_012345678901234567890123456789012345678901234567890123456789 == 33) | ||
515 | _012345678901234567890123456789012345678901234567890123456789 = nil | ||
516 | end | ||
517 | |||
518 | -- testing next | ||
519 | a = {} | ||
520 | t = pack(T.testC("next; return *", a, nil)) | ||
521 | tcheck(t, {n=1,a}) | ||
522 | a = {a=3} | ||
523 | t = pack(T.testC("next; return *", a, nil)) | ||
524 | tcheck(t, {n=3,a,'a',3}) | ||
525 | t = pack(T.testC("next; pop 1; next; return *", a, nil)) | ||
526 | tcheck(t, {n=1,a}) | ||
527 | |||
528 | |||
529 | |||
530 | -- testing upvalues | ||
531 | |||
532 | do | ||
533 | local A = T.testC[[ pushnum 10; pushnum 20; pushcclosure 2; return 1]] | ||
534 | t, b, c = A([[pushvalue U0; pushvalue U1; pushvalue U2; return 3]]) | ||
535 | assert(b == 10 and c == 20 and type(t) == 'table') | ||
536 | a, b = A([[tostring U3; tonumber U4; return 2]]) | ||
537 | assert(a == nil and b == 0) | ||
538 | A([[pushnum 100; pushnum 200; replace U2; replace U1]]) | ||
539 | b, c = A([[pushvalue U1; pushvalue U2; return 2]]) | ||
540 | assert(b == 100 and c == 200) | ||
541 | A([[replace U2; replace U1]], {x=1}, {x=2}) | ||
542 | b, c = A([[pushvalue U1; pushvalue U2; return 2]]) | ||
543 | assert(b.x == 1 and c.x == 2) | ||
544 | T.checkmemory() | ||
545 | end | ||
546 | |||
547 | |||
548 | -- testing absent upvalues from C-function pointers | ||
549 | assert(T.testC[[isnull U1; return 1]] == true) | ||
550 | assert(T.testC[[isnull U100; return 1]] == true) | ||
551 | assert(T.testC[[pushvalue U1; return 1]] == nil) | ||
552 | |||
553 | local f = T.testC[[ pushnum 10; pushnum 20; pushcclosure 2; return 1]] | ||
554 | assert(T.upvalue(f, 1) == 10 and | ||
555 | T.upvalue(f, 2) == 20 and | ||
556 | T.upvalue(f, 3) == nil) | ||
557 | T.upvalue(f, 2, "xuxu") | ||
558 | assert(T.upvalue(f, 2) == "xuxu") | ||
559 | |||
560 | |||
561 | -- large closures | ||
562 | do | ||
563 | local A = "checkstack 300 msg;" .. | ||
564 | string.rep("pushnum 10;", 255) .. | ||
565 | "pushcclosure 255; return 1" | ||
566 | A = T.testC(A) | ||
567 | for i=1,255 do | ||
568 | assert(A(("pushvalue U%d; return 1"):format(i)) == 10) | ||
569 | end | ||
570 | assert(A("isnull U256; return 1")) | ||
571 | assert(not A("isnil U256; return 1")) | ||
572 | end | ||
573 | |||
574 | |||
575 | |||
576 | -- testing get/setuservalue | ||
577 | -- bug in 5.1.2 | ||
578 | checkerr("got number", debug.setuservalue, 3, {}) | ||
579 | checkerr("got nil", debug.setuservalue, nil, {}) | ||
580 | checkerr("got light userdata", debug.setuservalue, T.pushuserdata(1), {}) | ||
581 | |||
582 | local b = T.newuserdata(0) | ||
583 | assert(debug.getuservalue(b) == nil) | ||
584 | for _, v in pairs{true, false, 4.56, print, {}, b, "XYZ"} do | ||
585 | assert(debug.setuservalue(b, v) == b) | ||
586 | assert(debug.getuservalue(b) == v) | ||
587 | end | ||
588 | |||
589 | assert(debug.getuservalue(4) == nil) | ||
590 | |||
591 | debug.setuservalue(b, function () return 10 end) | ||
592 | collectgarbage() -- function should not be collected | ||
593 | assert(debug.getuservalue(b)() == 10) | ||
594 | |||
595 | debug.setuservalue(b, 134) | ||
596 | collectgarbage() -- number should not be a problem for collector | ||
597 | assert(debug.getuservalue(b) == 134) | ||
598 | |||
599 | -- test barrier for uservalues | ||
600 | T.gcstate("atomic") | ||
601 | assert(T.gccolor(b) == "black") | ||
602 | debug.setuservalue(b, {x = 100}) | ||
603 | T.gcstate("pause") -- complete collection | ||
604 | assert(debug.getuservalue(b).x == 100) -- uvalue should be there | ||
605 | |||
606 | -- long chain of userdata | ||
607 | for i = 1, 1000 do | ||
608 | local bb = T.newuserdata(0) | ||
609 | debug.setuservalue(bb, b) | ||
610 | b = bb | ||
611 | end | ||
612 | collectgarbage() -- nothing should not be collected | ||
613 | for i = 1, 1000 do | ||
614 | b = debug.getuservalue(b) | ||
615 | end | ||
616 | assert(debug.getuservalue(b).x == 100) | ||
617 | b = nil | ||
618 | |||
619 | |||
620 | -- testing locks (refs) | ||
621 | |||
622 | -- reuse of references | ||
623 | local i = T.ref{} | ||
624 | T.unref(i) | ||
625 | assert(T.ref{} == i) | ||
626 | |||
627 | Arr = {} | ||
628 | Lim = 100 | ||
629 | for i=1,Lim do -- lock many objects | ||
630 | Arr[i] = T.ref({}) | ||
631 | end | ||
632 | |||
633 | assert(T.ref(nil) == -1 and T.getref(-1) == nil) | ||
634 | T.unref(-1); T.unref(-1) | ||
635 | |||
636 | for i=1,Lim do -- unlock all them | ||
637 | T.unref(Arr[i]) | ||
638 | end | ||
639 | |||
640 | function printlocks () | ||
641 | local f = T.makeCfunc("gettable R; return 1") | ||
642 | local n = f("n") | ||
643 | print("n", n) | ||
644 | for i=0,n do | ||
645 | print(i, f(i)) | ||
646 | end | ||
647 | end | ||
648 | |||
649 | |||
650 | for i=1,Lim do -- lock many objects | ||
651 | Arr[i] = T.ref({}) | ||
652 | end | ||
653 | |||
654 | for i=1,Lim,2 do -- unlock half of them | ||
655 | T.unref(Arr[i]) | ||
656 | end | ||
657 | |||
658 | assert(type(T.getref(Arr[2])) == 'table') | ||
659 | |||
660 | |||
661 | assert(T.getref(-1) == nil) | ||
662 | |||
663 | |||
664 | a = T.ref({}) | ||
665 | |||
666 | collectgarbage() | ||
667 | |||
668 | assert(type(T.getref(a)) == 'table') | ||
669 | |||
670 | |||
671 | -- colect in cl the `val' of all collected userdata | ||
672 | tt = {} | ||
673 | cl = {n=0} | ||
674 | A = nil; B = nil | ||
675 | local F | ||
676 | F = function (x) | ||
677 | local udval = T.udataval(x) | ||
678 | table.insert(cl, udval) | ||
679 | local d = T.newuserdata(100) -- cria lixo | ||
680 | d = nil | ||
681 | assert(debug.getmetatable(x).__gc == F) | ||
682 | assert(load("table.insert({}, {})"))() -- cria mais lixo | ||
683 | collectgarbage() -- forca coleta de lixo durante coleta! | ||
684 | assert(debug.getmetatable(x).__gc == F) -- coleta anterior nao melou isso? | ||
685 | local dummy = {} -- cria lixo durante coleta | ||
686 | if A ~= nil then | ||
687 | assert(type(A) == "userdata") | ||
688 | assert(T.udataval(A) == B) | ||
689 | debug.getmetatable(A) -- just acess it | ||
690 | end | ||
691 | A = x -- ressucita userdata | ||
692 | B = udval | ||
693 | return 1,2,3 | ||
694 | end | ||
695 | tt.__gc = F | ||
696 | |||
697 | -- test whether udate collection frees memory in the right time | ||
698 | do | ||
699 | collectgarbage(); | ||
700 | collectgarbage(); | ||
701 | local x = collectgarbage("count"); | ||
702 | local a = T.newuserdata(5001) | ||
703 | assert(T.testC("objsize 2; return 1", a) == 5001) | ||
704 | assert(collectgarbage("count") >= x+4) | ||
705 | a = nil | ||
706 | collectgarbage(); | ||
707 | assert(collectgarbage("count") <= x+1) | ||
708 | -- udata without finalizer | ||
709 | x = collectgarbage("count") | ||
710 | collectgarbage("stop") | ||
711 | for i=1,1000 do T.newuserdata(0) end | ||
712 | assert(collectgarbage("count") > x+10) | ||
713 | collectgarbage() | ||
714 | assert(collectgarbage("count") <= x+1) | ||
715 | -- udata with finalizer | ||
716 | collectgarbage() | ||
717 | x = collectgarbage("count") | ||
718 | collectgarbage("stop") | ||
719 | a = {__gc = function () end} | ||
720 | for i=1,1000 do debug.setmetatable(T.newuserdata(0), a) end | ||
721 | assert(collectgarbage("count") >= x+10) | ||
722 | collectgarbage() -- this collection only calls TM, without freeing memory | ||
723 | assert(collectgarbage("count") >= x+10) | ||
724 | collectgarbage() -- now frees memory | ||
725 | assert(collectgarbage("count") <= x+1) | ||
726 | collectgarbage("restart") | ||
727 | end | ||
728 | |||
729 | |||
730 | collectgarbage("stop") | ||
731 | |||
732 | -- create 3 userdatas with tag `tt' | ||
733 | a = T.newuserdata(0); debug.setmetatable(a, tt); na = T.udataval(a) | ||
734 | b = T.newuserdata(0); debug.setmetatable(b, tt); nb = T.udataval(b) | ||
735 | c = T.newuserdata(0); debug.setmetatable(c, tt); nc = T.udataval(c) | ||
736 | |||
737 | -- create userdata without meta table | ||
738 | x = T.newuserdata(4) | ||
739 | y = T.newuserdata(0) | ||
740 | |||
741 | checkerr("FILE%* expected, got userdata", io.input, a) | ||
742 | checkerr("FILE%* expected, got userdata", io.input, x) | ||
743 | |||
744 | assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil) | ||
745 | |||
746 | d=T.ref(a); | ||
747 | e=T.ref(b); | ||
748 | f=T.ref(c); | ||
749 | t = {T.getref(d), T.getref(e), T.getref(f)} | ||
750 | assert(t[1] == a and t[2] == b and t[3] == c) | ||
751 | |||
752 | t=nil; a=nil; c=nil; | ||
753 | T.unref(e); T.unref(f) | ||
754 | |||
755 | collectgarbage() | ||
756 | |||
757 | -- check that unref objects have been collected | ||
758 | assert(#cl == 1 and cl[1] == nc) | ||
759 | |||
760 | x = T.getref(d) | ||
761 | assert(type(x) == 'userdata' and debug.getmetatable(x) == tt) | ||
762 | x =nil | ||
763 | tt.b = b -- create cycle | ||
764 | tt=nil -- frees tt for GC | ||
765 | A = nil | ||
766 | b = nil | ||
767 | T.unref(d); | ||
768 | n5 = T.newuserdata(0) | ||
769 | debug.setmetatable(n5, {__gc=F}) | ||
770 | n5 = T.udataval(n5) | ||
771 | collectgarbage() | ||
772 | assert(#cl == 4) | ||
773 | -- check order of collection | ||
774 | assert(cl[2] == n5 and cl[3] == nb and cl[4] == na) | ||
775 | |||
776 | collectgarbage"restart" | ||
777 | |||
778 | |||
779 | a, na = {}, {} | ||
780 | for i=30,1,-1 do | ||
781 | a[i] = T.newuserdata(0) | ||
782 | debug.setmetatable(a[i], {__gc=F}) | ||
783 | na[i] = T.udataval(a[i]) | ||
784 | end | ||
785 | cl = {} | ||
786 | a = nil; collectgarbage() | ||
787 | assert(#cl == 30) | ||
788 | for i=1,30 do assert(cl[i] == na[i]) end | ||
789 | na = nil | ||
790 | |||
791 | |||
792 | for i=2,Lim,2 do -- unlock the other half | ||
793 | T.unref(Arr[i]) | ||
794 | end | ||
795 | |||
796 | x = T.newuserdata(41); debug.setmetatable(x, {__gc=F}) | ||
797 | assert(T.testC("objsize 2; return 1", x) == 41) | ||
798 | cl = {} | ||
799 | a = {[x] = 1} | ||
800 | x = T.udataval(x) | ||
801 | collectgarbage() | ||
802 | -- old `x' cannot be collected (`a' still uses it) | ||
803 | assert(#cl == 0) | ||
804 | for n in pairs(a) do a[n] = nil end | ||
805 | collectgarbage() | ||
806 | assert(#cl == 1 and cl[1] == x) -- old `x' must be collected | ||
807 | |||
808 | -- testing lua_equal | ||
809 | assert(T.testC("compare EQ 2 4; return 1", print, 1, print, 20)) | ||
810 | assert(T.testC("compare EQ 3 2; return 1", 'alo', "alo")) | ||
811 | assert(T.testC("compare EQ 2 3; return 1", nil, nil)) | ||
812 | assert(not T.testC("compare EQ 2 3; return 1", {}, {})) | ||
813 | assert(not T.testC("compare EQ 2 3; return 1")) | ||
814 | assert(not T.testC("compare EQ 2 3; return 1", 3)) | ||
815 | |||
816 | -- testing lua_equal with fallbacks | ||
817 | do | ||
818 | local map = {} | ||
819 | local t = {__eq = function (a,b) return map[a] == map[b] end} | ||
820 | local function f(x) | ||
821 | local u = T.newuserdata(0) | ||
822 | debug.setmetatable(u, t) | ||
823 | map[u] = x | ||
824 | return u | ||
825 | end | ||
826 | assert(f(10) == f(10)) | ||
827 | assert(f(10) ~= f(11)) | ||
828 | assert(T.testC("compare EQ 2 3; return 1", f(10), f(10))) | ||
829 | assert(not T.testC("compare EQ 2 3; return 1", f(10), f(20))) | ||
830 | t.__eq = nil | ||
831 | assert(f(10) ~= f(10)) | ||
832 | end | ||
833 | |||
834 | print'+' | ||
835 | |||
836 | |||
837 | |||
838 | -- testing changing hooks during hooks | ||
839 | _G.t = {} | ||
840 | T.sethook([[ | ||
841 | # set a line hook after 3 count hooks | ||
842 | sethook 4 0 ' | ||
843 | getglobal t; | ||
844 | pushvalue -3; append -2 | ||
845 | pushvalue -2; append -2 | ||
846 | ']], "c", 3) | ||
847 | local a = 1 -- counting | ||
848 | a = 1 -- counting | ||
849 | a = 1 -- count hook (set line hook) | ||
850 | a = 1 -- line hook | ||
851 | a = 1 -- line hook | ||
852 | debug.sethook() | ||
853 | t = _G.t | ||
854 | assert(t[1] == "line") | ||
855 | line = t[2] | ||
856 | assert(t[3] == "line" and t[4] == line + 1) | ||
857 | assert(t[5] == "line" and t[6] == line + 2) | ||
858 | assert(t[7] == nil) | ||
859 | |||
860 | |||
861 | ------------------------------------------------------------------------- | ||
862 | do -- testing errors during GC | ||
863 | local a = {} | ||
864 | for i=1,20 do | ||
865 | a[i] = T.newuserdata(i) -- creates several udata | ||
866 | end | ||
867 | for i=1,20,2 do -- mark half of them to raise errors during GC | ||
868 | debug.setmetatable(a[i], {__gc = function (x) error("error inside gc") end}) | ||
869 | end | ||
870 | for i=2,20,2 do -- mark the other half to count and to create more garbage | ||
871 | debug.setmetatable(a[i], {__gc = function (x) load("A=A+1")() end}) | ||
872 | end | ||
873 | _G.A = 0 | ||
874 | a = 0 | ||
875 | while 1 do | ||
876 | local stat, msg = pcall(collectgarbage) | ||
877 | if stat then | ||
878 | break -- stop when no more errors | ||
879 | else | ||
880 | a = a + 1 | ||
881 | assert(string.find(msg, "__gc")) | ||
882 | end | ||
883 | end | ||
884 | assert(a == 10) -- number of errors | ||
885 | |||
886 | assert(A == 10) -- number of normal collections | ||
887 | end | ||
888 | ------------------------------------------------------------------------- | ||
889 | -- test for userdata vals | ||
890 | do | ||
891 | local a = {}; local lim = 30 | ||
892 | for i=0,lim do a[i] = T.pushuserdata(i) end | ||
893 | for i=0,lim do assert(T.udataval(a[i]) == i) end | ||
894 | for i=0,lim do assert(T.pushuserdata(i) == a[i]) end | ||
895 | for i=0,lim do a[a[i]] = i end | ||
896 | for i=0,lim do a[T.pushuserdata(i)] = i end | ||
897 | assert(type(tostring(a[1])) == "string") | ||
898 | end | ||
899 | |||
900 | |||
901 | ------------------------------------------------------------------------- | ||
902 | -- testing multiple states | ||
903 | T.closestate(T.newstate()); | ||
904 | L1 = T.newstate() | ||
905 | assert(L1) | ||
906 | |||
907 | assert(T.doremote(L1, "X='a'; return 'a'") == 'a') | ||
908 | |||
909 | |||
910 | assert(#pack(T.doremote(L1, "function f () return 'alo', 3 end; f()")) == 0) | ||
911 | |||
912 | a, b = T.doremote(L1, "return f()") | ||
913 | assert(a == 'alo' and b == '3') | ||
914 | |||
915 | T.doremote(L1, "_ERRORMESSAGE = nil") | ||
916 | -- error: `sin' is not defined | ||
917 | a, _, b = T.doremote(L1, "return sin(1)") | ||
918 | assert(a == nil and b == 2) -- 2 == run-time error | ||
919 | |||
920 | -- error: syntax error | ||
921 | a, b, c = T.doremote(L1, "return a+") | ||
922 | assert(a == nil and c == 3 and type(b) == "string") -- 3 == syntax error | ||
923 | |||
924 | T.loadlib(L1) | ||
925 | a, b, c = T.doremote(L1, [[ | ||
926 | string = require'string' | ||
927 | a = require'_G'; assert(a == _G and require("_G") == a) | ||
928 | io = require'io'; assert(type(io.read) == "function") | ||
929 | assert(require("io") == io) | ||
930 | a = require'table'; assert(type(a.insert) == "function") | ||
931 | a = require'debug'; assert(type(a.getlocal) == "function") | ||
932 | a = require'math'; assert(type(a.sin) == "function") | ||
933 | return string.sub('okinama', 1, 2) | ||
934 | ]]) | ||
935 | assert(a == "ok") | ||
936 | |||
937 | T.closestate(L1); | ||
938 | |||
939 | |||
940 | L1 = T.newstate() | ||
941 | T.loadlib(L1) | ||
942 | T.doremote(L1, "a = {}") | ||
943 | T.testC(L1, [[getglobal "a"; pushstring "x"; pushint 1; | ||
944 | settable -3]]) | ||
945 | assert(T.doremote(L1, "return a.x") == "1") | ||
946 | |||
947 | T.closestate(L1) | ||
948 | |||
949 | L1 = nil | ||
950 | |||
951 | print('+') | ||
952 | |||
953 | ------------------------------------------------------------------------- | ||
954 | -- testing memory limits | ||
955 | ------------------------------------------------------------------------- | ||
956 | checkerr("block too big", T.newuserdata, math.maxinteger) | ||
957 | collectgarbage() | ||
958 | T.totalmem(T.totalmem()+5000) -- set low memory limit (+5k) | ||
959 | checkerr("not enough memory", load"local a={}; for i=1,100000 do a[i]=i end") | ||
960 | T.totalmem(0) -- restore high limit | ||
961 | |||
962 | -- test memory errors; increase memory limit in small steps, so that | ||
963 | -- we get memory errors in different parts of a given task, up to there | ||
964 | -- is enough memory to complete the task without errors | ||
965 | function testamem (s, f) | ||
966 | collectgarbage(); collectgarbage() | ||
967 | local M = T.totalmem() | ||
968 | local oldM = M | ||
969 | local a,b = nil | ||
970 | while 1 do | ||
971 | M = M+7 -- increase memory limit in small steps | ||
972 | T.totalmem(M) | ||
973 | a, b = pcall(f) | ||
974 | T.totalmem(0) -- restore high limit | ||
975 | if a and b then break end -- stop when no more errors | ||
976 | collectgarbage() | ||
977 | if not a and not -- `real' error? | ||
978 | (string.find(b, "memory") or string.find(b, "overflow")) then | ||
979 | error(b, 0) -- propagate it | ||
980 | end | ||
981 | end | ||
982 | print("\nlimit for " .. s .. ": " .. M-oldM) | ||
983 | return b | ||
984 | end | ||
985 | |||
986 | |||
987 | -- testing memory errors when creating a new state | ||
988 | |||
989 | b = testamem("state creation", T.newstate) | ||
990 | T.closestate(b); -- close new state | ||
991 | |||
992 | |||
993 | -- testing threads | ||
994 | |||
995 | -- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1) | ||
996 | mt = T.testC("rawgeti R 1; return 1") | ||
997 | assert(type(mt) == "thread" and coroutine.running() == mt) | ||
998 | |||
999 | |||
1000 | |||
1001 | function expand (n,s) | ||
1002 | if n==0 then return "" end | ||
1003 | local e = string.rep("=", n) | ||
1004 | return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n", | ||
1005 | e, s, expand(n-1,s), e) | ||
1006 | end | ||
1007 | |||
1008 | G=0; collectgarbage(); a =collectgarbage("count") | ||
1009 | load(expand(20,"G=G+1"))() | ||
1010 | assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1) | ||
1011 | |||
1012 | testamem("thread creation", function () | ||
1013 | return T.doonnewstack("x=1") == 0 -- try to create thread | ||
1014 | end) | ||
1015 | |||
1016 | |||
1017 | -- testing memory x compiler | ||
1018 | |||
1019 | testamem("loadstring", function () | ||
1020 | return load("x=1") -- try to do load a string | ||
1021 | end) | ||
1022 | |||
1023 | |||
1024 | local testprog = [[ | ||
1025 | local function foo () return end | ||
1026 | local t = {"x"} | ||
1027 | a = "aaa" | ||
1028 | for i = 1, #t do a=a..t[i] end | ||
1029 | return true | ||
1030 | ]] | ||
1031 | |||
1032 | -- testing memory x dofile | ||
1033 | _G.a = nil | ||
1034 | local t =os.tmpname() | ||
1035 | local f = assert(io.open(t, "w")) | ||
1036 | f:write(testprog) | ||
1037 | f:close() | ||
1038 | testamem("dofile", function () | ||
1039 | local a = loadfile(t) | ||
1040 | return a and a() | ||
1041 | end) | ||
1042 | assert(os.remove(t)) | ||
1043 | assert(_G.a == "aaax") | ||
1044 | |||
1045 | |||
1046 | -- other generic tests | ||
1047 | |||
1048 | testamem("string creation", function () | ||
1049 | local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end) | ||
1050 | return (a == 'ablo ablo') | ||
1051 | end) | ||
1052 | |||
1053 | testamem("dump/undump", function () | ||
1054 | local a = load(testprog) | ||
1055 | local b = a and string.dump(a) | ||
1056 | a = b and load(b) | ||
1057 | return a and a() | ||
1058 | end) | ||
1059 | |||
1060 | local t = os.tmpname() | ||
1061 | testamem("file creation", function () | ||
1062 | local f = assert(io.open(t, 'w')) | ||
1063 | assert (not io.open"nomenaoexistente") | ||
1064 | io.close(f); | ||
1065 | return not loadfile'nomenaoexistente' | ||
1066 | end) | ||
1067 | assert(os.remove(t)) | ||
1068 | |||
1069 | testamem("table creation", function () | ||
1070 | local a, lim = {}, 10 | ||
1071 | for i=1,lim do a[i] = i; a[i..'a'] = {} end | ||
1072 | return (type(a[lim..'a']) == 'table' and a[lim] == lim) | ||
1073 | end) | ||
1074 | |||
1075 | testamem("constructors", function () | ||
1076 | local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5} | ||
1077 | return (type(a) == 'table' and a.e == 5) | ||
1078 | end) | ||
1079 | |||
1080 | local a = 1 | ||
1081 | close = nil | ||
1082 | testamem("closure creation", function () | ||
1083 | function close (b,c) | ||
1084 | return function (x) return a+b+c+x end | ||
1085 | end | ||
1086 | return (close(2,3)(4) == 10) | ||
1087 | end) | ||
1088 | |||
1089 | testamem("coroutines", function () | ||
1090 | local a = coroutine.wrap(function () | ||
1091 | coroutine.yield(string.rep("a", 10)) | ||
1092 | return {} | ||
1093 | end) | ||
1094 | assert(string.len(a()) == 10) | ||
1095 | return a() | ||
1096 | end) | ||
1097 | |||
1098 | do -- auxiliary buffer | ||
1099 | local lim = 100 | ||
1100 | local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end | ||
1101 | testamem("auxiliary buffer", function () | ||
1102 | return (#table.concat(a, ",") == 20*lim + lim - 1) | ||
1103 | end) | ||
1104 | end | ||
1105 | |||
1106 | print'+' | ||
1107 | |||
1108 | -- testing some auxlib functions | ||
1109 | local function gsub (a, b, c) | ||
1110 | a, b = T.testC("gsub 2 3 4; gettop; return 2", a, b, c) | ||
1111 | assert(b == 5) | ||
1112 | return a | ||
1113 | end | ||
1114 | |||
1115 | assert(gsub("alo.alo.uhuh.", ".", "//") == "alo//alo//uhuh//") | ||
1116 | assert(gsub("alo.alo.uhuh.", "alo", "//") == "//.//.uhuh.") | ||
1117 | assert(gsub("", "alo", "//") == "") | ||
1118 | assert(gsub("...", ".", "/.") == "/././.") | ||
1119 | assert(gsub("...", "...", "") == "") | ||
1120 | |||
1121 | |||
1122 | -- testing luaL_newmetatable | ||
1123 | local mt_xuxu, res, top = T.testC("newmetatable xuxu; gettop; return 3") | ||
1124 | assert(type(mt_xuxu) == "table" and res and top == 3) | ||
1125 | local d, res, top = T.testC("newmetatable xuxu; gettop; return 3") | ||
1126 | assert(mt_xuxu == d and not res and top == 3) | ||
1127 | d, res, top = T.testC("newmetatable xuxu1; gettop; return 3") | ||
1128 | assert(mt_xuxu ~= d and res and top == 3) | ||
1129 | |||
1130 | x = T.newuserdata(0); | ||
1131 | y = T.newuserdata(0); | ||
1132 | T.testC("pushstring xuxu; gettable R; setmetatable 2", x) | ||
1133 | assert(getmetatable(x) == mt_xuxu) | ||
1134 | |||
1135 | -- testing luaL_testudata | ||
1136 | -- correct metatable | ||
1137 | local res1, res2, top = T.testC([[testudata -1 xuxu | ||
1138 | testudata 2 xuxu | ||
1139 | gettop | ||
1140 | return 3]], x) | ||
1141 | assert(res1 and res2 and top == 4) | ||
1142 | |||
1143 | -- wrong metatable | ||
1144 | res1, res2, top = T.testC([[testudata -1 xuxu1 | ||
1145 | testudata 2 xuxu1 | ||
1146 | gettop | ||
1147 | return 3]], x) | ||
1148 | assert(not res1 and not res2 and top == 4) | ||
1149 | |||
1150 | -- non-existent type | ||
1151 | res1, res2, top = T.testC([[testudata -1 xuxu2 | ||
1152 | testudata 2 xuxu2 | ||
1153 | gettop | ||
1154 | return 3]], x) | ||
1155 | assert(not res1 and not res2 and top == 4) | ||
1156 | |||
1157 | -- userdata has no metatable | ||
1158 | res1, res2, top = T.testC([[testudata -1 xuxu | ||
1159 | testudata 2 xuxu | ||
1160 | gettop | ||
1161 | return 3]], y) | ||
1162 | assert(not res1 and not res2 and top == 4) | ||
1163 | |||
1164 | -- erase metatables | ||
1165 | do | ||
1166 | local r = debug.getregistry() | ||
1167 | assert(r.xuxu == mt_xuxu and r.xuxu1 == d) | ||
1168 | r.xuxu = nil; r.xuxu1 = nil | ||
1169 | end | ||
1170 | |||
1171 | print'OK' | ||
1172 | |||