diff options
Diffstat (limited to 'testes/files.lua')
-rw-r--r-- | testes/files.lua | 793 |
1 files changed, 793 insertions, 0 deletions
diff --git a/testes/files.lua b/testes/files.lua new file mode 100644 index 00000000..3cfe12d2 --- /dev/null +++ b/testes/files.lua | |||
@@ -0,0 +1,793 @@ | |||
1 | -- $Id: files.lua,v 1.95 2016/11/07 13:11:28 roberto Exp $ | ||
2 | -- See Copyright Notice in file all.lua | ||
3 | |||
4 | local debug = require "debug" | ||
5 | |||
6 | local maxint = math.maxinteger | ||
7 | |||
8 | assert(type(os.getenv"PATH") == "string") | ||
9 | |||
10 | assert(io.input(io.stdin) == io.stdin) | ||
11 | assert(not pcall(io.input, "non-existent-file")) | ||
12 | assert(io.output(io.stdout) == io.stdout) | ||
13 | |||
14 | |||
15 | local function testerr (msg, f, ...) | ||
16 | local stat, err = pcall(f, ...) | ||
17 | return (not stat and string.find(err, msg, 1, true)) | ||
18 | end | ||
19 | |||
20 | |||
21 | local function checkerr (msg, f, ...) | ||
22 | assert(testerr(msg, f, ...)) | ||
23 | end | ||
24 | |||
25 | |||
26 | -- cannot close standard files | ||
27 | assert(not io.close(io.stdin) and | ||
28 | not io.stdout:close() and | ||
29 | not io.stderr:close()) | ||
30 | |||
31 | |||
32 | assert(type(io.input()) == "userdata" and io.type(io.output()) == "file") | ||
33 | assert(type(io.stdin) == "userdata" and io.type(io.stderr) == "file") | ||
34 | assert(not io.type(8)) | ||
35 | local a = {}; setmetatable(a, {}) | ||
36 | assert(not io.type(a)) | ||
37 | |||
38 | assert(getmetatable(io.input()).__name == "FILE*") | ||
39 | |||
40 | local a,b,c = io.open('xuxu_nao_existe') | ||
41 | assert(not a and type(b) == "string" and type(c) == "number") | ||
42 | |||
43 | a,b,c = io.open('/a/b/c/d', 'w') | ||
44 | assert(not a and type(b) == "string" and type(c) == "number") | ||
45 | |||
46 | local file = os.tmpname() | ||
47 | local f, msg = io.open(file, "w") | ||
48 | if not f then | ||
49 | (Message or print)("'os.tmpname' file cannot be open; skipping file tests") | ||
50 | |||
51 | else --{ most tests here need tmpname | ||
52 | f:close() | ||
53 | |||
54 | print('testing i/o') | ||
55 | |||
56 | local otherfile = os.tmpname() | ||
57 | |||
58 | checkerr("invalid mode", io.open, file, "rw") | ||
59 | checkerr("invalid mode", io.open, file, "rb+") | ||
60 | checkerr("invalid mode", io.open, file, "r+bk") | ||
61 | checkerr("invalid mode", io.open, file, "") | ||
62 | checkerr("invalid mode", io.open, file, "+") | ||
63 | checkerr("invalid mode", io.open, file, "b") | ||
64 | assert(io.open(file, "r+b")):close() | ||
65 | assert(io.open(file, "r+")):close() | ||
66 | assert(io.open(file, "rb")):close() | ||
67 | |||
68 | assert(os.setlocale('C', 'all')) | ||
69 | |||
70 | io.input(io.stdin); io.output(io.stdout); | ||
71 | |||
72 | os.remove(file) | ||
73 | assert(not loadfile(file)) | ||
74 | checkerr("", dofile, file) | ||
75 | assert(not io.open(file)) | ||
76 | io.output(file) | ||
77 | assert(io.output() ~= io.stdout) | ||
78 | |||
79 | if not _port then -- invalid seek | ||
80 | local status, msg, code = io.stdin:seek("set", 1000) | ||
81 | assert(not status and type(msg) == "string" and type(code) == "number") | ||
82 | end | ||
83 | |||
84 | assert(io.output():seek() == 0) | ||
85 | assert(io.write("alo alo"):seek() == string.len("alo alo")) | ||
86 | assert(io.output():seek("cur", -3) == string.len("alo alo")-3) | ||
87 | assert(io.write("joao")) | ||
88 | assert(io.output():seek("end") == string.len("alo joao")) | ||
89 | |||
90 | assert(io.output():seek("set") == 0) | ||
91 | |||
92 | assert(io.write('"álo"', "{a}\n", "second line\n", "third line \n")) | ||
93 | assert(io.write('çfourth_line')) | ||
94 | io.output(io.stdout) | ||
95 | collectgarbage() -- file should be closed by GC | ||
96 | assert(io.input() == io.stdin and rawequal(io.output(), io.stdout)) | ||
97 | print('+') | ||
98 | |||
99 | -- test GC for files | ||
100 | collectgarbage() | ||
101 | for i=1,120 do | ||
102 | for i=1,5 do | ||
103 | io.input(file) | ||
104 | assert(io.open(file, 'r')) | ||
105 | io.lines(file) | ||
106 | end | ||
107 | collectgarbage() | ||
108 | end | ||
109 | |||
110 | io.input():close() | ||
111 | io.close() | ||
112 | |||
113 | assert(os.rename(file, otherfile)) | ||
114 | assert(not os.rename(file, otherfile)) | ||
115 | |||
116 | io.output(io.open(otherfile, "ab")) | ||
117 | assert(io.write("\n\n\t\t ", 3450, "\n")); | ||
118 | io.close() | ||
119 | |||
120 | -- test writing/reading numbers | ||
121 | f = assert(io.open(file, "w")) | ||
122 | f:write(maxint, '\n') | ||
123 | f:write(string.format("0X%x\n", maxint)) | ||
124 | f:write("0xABCp-3", '\n') | ||
125 | f:write(0, '\n') | ||
126 | f:write(-maxint, '\n') | ||
127 | f:write(string.format("0x%X\n", -maxint)) | ||
128 | f:write("-0xABCp-3", '\n') | ||
129 | assert(f:close()) | ||
130 | f = assert(io.open(file, "r")) | ||
131 | assert(f:read("n") == maxint) | ||
132 | assert(f:read("n") == maxint) | ||
133 | assert(f:read("n") == 0xABCp-3) | ||
134 | assert(f:read("n") == 0) | ||
135 | assert(f:read("*n") == -maxint) -- test old format (with '*') | ||
136 | assert(f:read("n") == -maxint) | ||
137 | assert(f:read("*n") == -0xABCp-3) -- test old format (with '*') | ||
138 | assert(f:close()) | ||
139 | assert(os.remove(file)) | ||
140 | |||
141 | -- test yielding during 'dofile' | ||
142 | f = assert(io.open(file, "w")) | ||
143 | f:write[[ | ||
144 | local x, z = coroutine.yield(10) | ||
145 | local y = coroutine.yield(20) | ||
146 | return x + y * z | ||
147 | ]] | ||
148 | assert(f:close()) | ||
149 | f = coroutine.wrap(dofile) | ||
150 | assert(f(file) == 10) | ||
151 | print(f(100, 101) == 20) | ||
152 | assert(f(200) == 100 + 200 * 101) | ||
153 | assert(os.remove(file)) | ||
154 | |||
155 | |||
156 | f = assert(io.open(file, "w")) | ||
157 | -- test number termination | ||
158 | f:write[[ | ||
159 | -12.3- -0xffff+ .3|5.E-3X +234e+13E 0xDEADBEEFDEADBEEFx | ||
160 | 0x1.13Ap+3e | ||
161 | ]] | ||
162 | -- very long number | ||
163 | f:write("1234"); for i = 1, 1000 do f:write("0") end; f:write("\n") | ||
164 | -- invalid sequences (must read and discard valid prefixes) | ||
165 | f:write[[ | ||
166 | .e+ 0.e; --; 0xX; | ||
167 | ]] | ||
168 | assert(f:close()) | ||
169 | f = assert(io.open(file, "r")) | ||
170 | assert(f:read("n") == -12.3); assert(f:read(1) == "-") | ||
171 | assert(f:read("n") == -0xffff); assert(f:read(2) == "+ ") | ||
172 | assert(f:read("n") == 0.3); assert(f:read(1) == "|") | ||
173 | assert(f:read("n") == 5e-3); assert(f:read(1) == "X") | ||
174 | assert(f:read("n") == 234e13); assert(f:read(1) == "E") | ||
175 | assert(f:read("n") == 0Xdeadbeefdeadbeef); assert(f:read(2) == "x\n") | ||
176 | assert(f:read("n") == 0x1.13aP3); assert(f:read(1) == "e") | ||
177 | |||
178 | do -- attempt to read too long number | ||
179 | assert(f:read("n") == nil) -- fails | ||
180 | local s = f:read("L") -- read rest of line | ||
181 | assert(string.find(s, "^00*\n$")) -- lots of 0's left | ||
182 | end | ||
183 | |||
184 | assert(not f:read("n")); assert(f:read(2) == "e+") | ||
185 | assert(not f:read("n")); assert(f:read(1) == ";") | ||
186 | assert(not f:read("n")); assert(f:read(2) == "-;") | ||
187 | assert(not f:read("n")); assert(f:read(1) == "X") | ||
188 | assert(not f:read("n")); assert(f:read(1) == ";") | ||
189 | assert(not f:read("n")); assert(not f:read(0)) -- end of file | ||
190 | assert(f:close()) | ||
191 | assert(os.remove(file)) | ||
192 | |||
193 | |||
194 | -- test line generators | ||
195 | assert(not pcall(io.lines, "non-existent-file")) | ||
196 | assert(os.rename(otherfile, file)) | ||
197 | io.output(otherfile) | ||
198 | local n = 0 | ||
199 | local f = io.lines(file) | ||
200 | while f() do n = n + 1 end; | ||
201 | assert(n == 6) -- number of lines in the file | ||
202 | checkerr("file is already closed", f) | ||
203 | checkerr("file is already closed", f) | ||
204 | -- copy from file to otherfile | ||
205 | n = 0 | ||
206 | for l in io.lines(file) do io.write(l, "\n"); n = n + 1 end | ||
207 | io.close() | ||
208 | assert(n == 6) | ||
209 | -- copy from otherfile back to file | ||
210 | local f = assert(io.open(otherfile)) | ||
211 | assert(io.type(f) == "file") | ||
212 | io.output(file) | ||
213 | assert(not io.output():read()) | ||
214 | n = 0 | ||
215 | for l in f:lines() do io.write(l, "\n"); n = n + 1 end | ||
216 | assert(tostring(f):sub(1, 5) == "file ") | ||
217 | assert(f:close()); io.close() | ||
218 | assert(n == 6) | ||
219 | checkerr("closed file", io.close, f) | ||
220 | assert(tostring(f) == "file (closed)") | ||
221 | assert(io.type(f) == "closed file") | ||
222 | io.input(file) | ||
223 | f = io.open(otherfile):lines() | ||
224 | n = 0 | ||
225 | for l in io.lines() do assert(l == f()); n = n + 1 end | ||
226 | f = nil; collectgarbage() | ||
227 | assert(n == 6) | ||
228 | assert(os.remove(otherfile)) | ||
229 | |||
230 | do -- bug in 5.3.1 | ||
231 | io.output(otherfile) | ||
232 | io.write(string.rep("a", 300), "\n") | ||
233 | io.close() | ||
234 | local t ={}; for i = 1, 250 do t[i] = 1 end | ||
235 | t = {io.lines(otherfile, table.unpack(t))()} | ||
236 | -- everything ok here | ||
237 | assert(#t == 250 and t[1] == 'a' and t[#t] == 'a') | ||
238 | t[#t + 1] = 1 -- one too many | ||
239 | checkerr("too many arguments", io.lines, otherfile, table.unpack(t)) | ||
240 | collectgarbage() -- ensure 'otherfile' is closed | ||
241 | assert(os.remove(otherfile)) | ||
242 | end | ||
243 | |||
244 | io.input(file) | ||
245 | do -- test error returns | ||
246 | local a,b,c = io.input():write("xuxu") | ||
247 | assert(not a and type(b) == "string" and type(c) == "number") | ||
248 | end | ||
249 | checkerr("invalid format", io.read, "x") | ||
250 | assert(io.read(0) == "") -- not eof | ||
251 | assert(io.read(5, 'l') == '"álo"') | ||
252 | assert(io.read(0) == "") | ||
253 | assert(io.read() == "second line") | ||
254 | local x = io.input():seek() | ||
255 | assert(io.read() == "third line ") | ||
256 | assert(io.input():seek("set", x)) | ||
257 | assert(io.read('L') == "third line \n") | ||
258 | assert(io.read(1) == "ç") | ||
259 | assert(io.read(string.len"fourth_line") == "fourth_line") | ||
260 | assert(io.input():seek("cur", -string.len"fourth_line")) | ||
261 | assert(io.read() == "fourth_line") | ||
262 | assert(io.read() == "") -- empty line | ||
263 | assert(io.read('n') == 3450) | ||
264 | assert(io.read(1) == '\n') | ||
265 | assert(io.read(0) == nil) -- end of file | ||
266 | assert(io.read(1) == nil) -- end of file | ||
267 | assert(io.read(30000) == nil) -- end of file | ||
268 | assert(({io.read(1)})[2] == nil) | ||
269 | assert(io.read() == nil) -- end of file | ||
270 | assert(({io.read()})[2] == nil) | ||
271 | assert(io.read('n') == nil) -- end of file | ||
272 | assert(({io.read('n')})[2] == nil) | ||
273 | assert(io.read('a') == '') -- end of file (OK for 'a') | ||
274 | assert(io.read('a') == '') -- end of file (OK for 'a') | ||
275 | collectgarbage() | ||
276 | print('+') | ||
277 | io.close(io.input()) | ||
278 | checkerr(" input file is closed", io.read) | ||
279 | |||
280 | assert(os.remove(file)) | ||
281 | |||
282 | local t = '0123456789' | ||
283 | for i=1,10 do t = t..t; end | ||
284 | assert(string.len(t) == 10*2^10) | ||
285 | |||
286 | io.output(file) | ||
287 | io.write("alo"):write("\n") | ||
288 | io.close() | ||
289 | checkerr(" output file is closed", io.write) | ||
290 | local f = io.open(file, "a+b") | ||
291 | io.output(f) | ||
292 | collectgarbage() | ||
293 | |||
294 | assert(io.write(' ' .. t .. ' ')) | ||
295 | assert(io.write(';', 'end of file\n')) | ||
296 | f:flush(); io.flush() | ||
297 | f:close() | ||
298 | print('+') | ||
299 | |||
300 | io.input(file) | ||
301 | assert(io.read() == "alo") | ||
302 | assert(io.read(1) == ' ') | ||
303 | assert(io.read(string.len(t)) == t) | ||
304 | assert(io.read(1) == ' ') | ||
305 | assert(io.read(0)) | ||
306 | assert(io.read('a') == ';end of file\n') | ||
307 | assert(io.read(0) == nil) | ||
308 | assert(io.close(io.input())) | ||
309 | |||
310 | |||
311 | -- test errors in read/write | ||
312 | do | ||
313 | local function ismsg (m) | ||
314 | -- error message is not a code number | ||
315 | return (type(m) == "string" and tonumber(m) == nil) | ||
316 | end | ||
317 | |||
318 | -- read | ||
319 | local f = io.open(file, "w") | ||
320 | local r, m, c = f:read() | ||
321 | assert(not r and ismsg(m) and type(c) == "number") | ||
322 | assert(f:close()) | ||
323 | -- write | ||
324 | f = io.open(file, "r") | ||
325 | r, m, c = f:write("whatever") | ||
326 | assert(not r and ismsg(m) and type(c) == "number") | ||
327 | assert(f:close()) | ||
328 | -- lines | ||
329 | f = io.open(file, "w") | ||
330 | r, m = pcall(f:lines()) | ||
331 | assert(r == false and ismsg(m)) | ||
332 | assert(f:close()) | ||
333 | end | ||
334 | |||
335 | assert(os.remove(file)) | ||
336 | |||
337 | -- test for L format | ||
338 | io.output(file); io.write"\n\nline\nother":close() | ||
339 | io.input(file) | ||
340 | assert(io.read"L" == "\n") | ||
341 | assert(io.read"L" == "\n") | ||
342 | assert(io.read"L" == "line\n") | ||
343 | assert(io.read"L" == "other") | ||
344 | assert(io.read"L" == nil) | ||
345 | io.input():close() | ||
346 | |||
347 | local f = assert(io.open(file)) | ||
348 | local s = "" | ||
349 | for l in f:lines("L") do s = s .. l end | ||
350 | assert(s == "\n\nline\nother") | ||
351 | f:close() | ||
352 | |||
353 | io.input(file) | ||
354 | s = "" | ||
355 | for l in io.lines(nil, "L") do s = s .. l end | ||
356 | assert(s == "\n\nline\nother") | ||
357 | io.input():close() | ||
358 | |||
359 | s = "" | ||
360 | for l in io.lines(file, "L") do s = s .. l end | ||
361 | assert(s == "\n\nline\nother") | ||
362 | |||
363 | s = "" | ||
364 | for l in io.lines(file, "l") do s = s .. l end | ||
365 | assert(s == "lineother") | ||
366 | |||
367 | io.output(file); io.write"a = 10 + 34\na = 2*a\na = -a\n":close() | ||
368 | local t = {} | ||
369 | load(io.lines(file, "L"), nil, nil, t)() | ||
370 | assert(t.a == -((10 + 34) * 2)) | ||
371 | |||
372 | |||
373 | -- test for multipe arguments in 'lines' | ||
374 | io.output(file); io.write"0123456789\n":close() | ||
375 | for a,b in io.lines(file, 1, 1) do | ||
376 | if a == "\n" then assert(b == nil) | ||
377 | else assert(tonumber(a) == tonumber(b) - 1) | ||
378 | end | ||
379 | end | ||
380 | |||
381 | for a,b,c in io.lines(file, 1, 2, "a") do | ||
382 | assert(a == "0" and b == "12" and c == "3456789\n") | ||
383 | end | ||
384 | |||
385 | for a,b,c in io.lines(file, "a", 0, 1) do | ||
386 | if a == "" then break end | ||
387 | assert(a == "0123456789\n" and b == nil and c == nil) | ||
388 | end | ||
389 | collectgarbage() -- to close file in previous iteration | ||
390 | |||
391 | io.output(file); io.write"00\n10\n20\n30\n40\n":close() | ||
392 | for a, b in io.lines(file, "n", "n") do | ||
393 | if a == 40 then assert(b == nil) | ||
394 | else assert(a == b - 10) | ||
395 | end | ||
396 | end | ||
397 | |||
398 | |||
399 | -- test load x lines | ||
400 | io.output(file); | ||
401 | io.write[[ | ||
402 | local y | ||
403 | = X | ||
404 | X = | ||
405 | X * | ||
406 | 2 + | ||
407 | X; | ||
408 | X = | ||
409 | X | ||
410 | - y; | ||
411 | ]]:close() | ||
412 | _G.X = 1 | ||
413 | assert(not load(io.lines(file))) | ||
414 | collectgarbage() -- to close file in previous iteration | ||
415 | load(io.lines(file, "L"))() | ||
416 | assert(_G.X == 2) | ||
417 | load(io.lines(file, 1))() | ||
418 | assert(_G.X == 4) | ||
419 | load(io.lines(file, 3))() | ||
420 | assert(_G.X == 8) | ||
421 | |||
422 | print('+') | ||
423 | |||
424 | local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'" | ||
425 | io.output(file) | ||
426 | assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1))) | ||
427 | io.close() | ||
428 | assert(loadfile(file))() | ||
429 | assert(x1 == x2) | ||
430 | print('+') | ||
431 | assert(os.remove(file)) | ||
432 | assert(not os.remove(file)) | ||
433 | assert(not os.remove(otherfile)) | ||
434 | |||
435 | -- testing loadfile | ||
436 | local function testloadfile (s, expres) | ||
437 | io.output(file) | ||
438 | if s then io.write(s) end | ||
439 | io.close() | ||
440 | local res = assert(loadfile(file))() | ||
441 | assert(os.remove(file)) | ||
442 | assert(res == expres) | ||
443 | end | ||
444 | |||
445 | -- loading empty file | ||
446 | testloadfile(nil, nil) | ||
447 | |||
448 | -- loading file with initial comment without end of line | ||
449 | testloadfile("# a non-ending comment", nil) | ||
450 | |||
451 | |||
452 | -- checking Unicode BOM in files | ||
453 | testloadfile("\xEF\xBB\xBF# some comment\nreturn 234", 234) | ||
454 | testloadfile("\xEF\xBB\xBFreturn 239", 239) | ||
455 | testloadfile("\xEF\xBB\xBF", nil) -- empty file with a BOM | ||
456 | |||
457 | |||
458 | -- checking line numbers in files with initial comments | ||
459 | testloadfile("# a comment\nreturn require'debug'.getinfo(1).currentline", 2) | ||
460 | |||
461 | |||
462 | -- loading binary file | ||
463 | io.output(io.open(file, "wb")) | ||
464 | assert(io.write(string.dump(function () return 10, '\0alo\255', 'hi' end))) | ||
465 | io.close() | ||
466 | a, b, c = assert(loadfile(file))() | ||
467 | assert(a == 10 and b == "\0alo\255" and c == "hi") | ||
468 | assert(os.remove(file)) | ||
469 | |||
470 | -- bug in 5.2.1 | ||
471 | do | ||
472 | io.output(io.open(file, "wb")) | ||
473 | -- save function with no upvalues | ||
474 | assert(io.write(string.dump(function () return 1 end))) | ||
475 | io.close() | ||
476 | f = assert(loadfile(file, "b", {})) | ||
477 | assert(type(f) == "function" and f() == 1) | ||
478 | assert(os.remove(file)) | ||
479 | end | ||
480 | |||
481 | -- loading binary file with initial comment | ||
482 | io.output(io.open(file, "wb")) | ||
483 | assert(io.write("#this is a comment for a binary file\0\n", | ||
484 | string.dump(function () return 20, '\0\0\0' end))) | ||
485 | io.close() | ||
486 | a, b, c = assert(loadfile(file))() | ||
487 | assert(a == 20 and b == "\0\0\0" and c == nil) | ||
488 | assert(os.remove(file)) | ||
489 | |||
490 | |||
491 | -- 'loadfile' with 'env' | ||
492 | do | ||
493 | local f = io.open(file, 'w') | ||
494 | f:write[[ | ||
495 | if (...) then a = 15; return b, c, d | ||
496 | else return _ENV | ||
497 | end | ||
498 | ]] | ||
499 | f:close() | ||
500 | local t = {b = 12, c = "xuxu", d = print} | ||
501 | local f = assert(loadfile(file, 't', t)) | ||
502 | local b, c, d = f(1) | ||
503 | assert(t.a == 15 and b == 12 and c == t.c and d == print) | ||
504 | assert(f() == t) | ||
505 | f = assert(loadfile(file, 't', nil)) | ||
506 | assert(f() == nil) | ||
507 | f = assert(loadfile(file)) | ||
508 | assert(f() == _G) | ||
509 | assert(os.remove(file)) | ||
510 | end | ||
511 | |||
512 | |||
513 | -- 'loadfile' x modes | ||
514 | do | ||
515 | io.open(file, 'w'):write("return 10"):close() | ||
516 | local s, m = loadfile(file, 'b') | ||
517 | assert(not s and string.find(m, "a text chunk")) | ||
518 | io.open(file, 'w'):write("\27 return 10"):close() | ||
519 | local s, m = loadfile(file, 't') | ||
520 | assert(not s and string.find(m, "a binary chunk")) | ||
521 | assert(os.remove(file)) | ||
522 | end | ||
523 | |||
524 | |||
525 | io.output(file) | ||
526 | assert(io.write("qualquer coisa\n")) | ||
527 | assert(io.write("mais qualquer coisa")) | ||
528 | io.close() | ||
529 | assert(io.output(assert(io.open(otherfile, 'wb'))) | ||
530 | :write("outra coisa\0\1\3\0\0\0\0\255\0") | ||
531 | :close()) | ||
532 | |||
533 | local filehandle = assert(io.open(file, 'r+')) | ||
534 | local otherfilehandle = assert(io.open(otherfile, 'rb')) | ||
535 | assert(filehandle ~= otherfilehandle) | ||
536 | assert(type(filehandle) == "userdata") | ||
537 | assert(filehandle:read('l') == "qualquer coisa") | ||
538 | io.input(otherfilehandle) | ||
539 | assert(io.read(string.len"outra coisa") == "outra coisa") | ||
540 | assert(filehandle:read('l') == "mais qualquer coisa") | ||
541 | filehandle:close(); | ||
542 | assert(type(filehandle) == "userdata") | ||
543 | io.input(otherfilehandle) | ||
544 | assert(io.read(4) == "\0\1\3\0") | ||
545 | assert(io.read(3) == "\0\0\0") | ||
546 | assert(io.read(0) == "") -- 255 is not eof | ||
547 | assert(io.read(1) == "\255") | ||
548 | assert(io.read('a') == "\0") | ||
549 | assert(not io.read(0)) | ||
550 | assert(otherfilehandle == io.input()) | ||
551 | otherfilehandle:close() | ||
552 | assert(os.remove(file)) | ||
553 | assert(os.remove(otherfile)) | ||
554 | collectgarbage() | ||
555 | |||
556 | io.output(file) | ||
557 | :write[[ | ||
558 | 123.4 -56e-2 not a number | ||
559 | second line | ||
560 | third line | ||
561 | |||
562 | and the rest of the file | ||
563 | ]] | ||
564 | :close() | ||
565 | io.input(file) | ||
566 | local _,a,b,c,d,e,h,__ = io.read(1, 'n', 'n', 'l', 'l', 'l', 'a', 10) | ||
567 | assert(io.close(io.input())) | ||
568 | assert(_ == ' ' and __ == nil) | ||
569 | assert(type(a) == 'number' and a==123.4 and b==-56e-2) | ||
570 | assert(d=='second line' and e=='third line') | ||
571 | assert(h==[[ | ||
572 | |||
573 | and the rest of the file | ||
574 | ]]) | ||
575 | assert(os.remove(file)) | ||
576 | collectgarbage() | ||
577 | |||
578 | -- testing buffers | ||
579 | do | ||
580 | local f = assert(io.open(file, "w")) | ||
581 | local fr = assert(io.open(file, "r")) | ||
582 | assert(f:setvbuf("full", 2000)) | ||
583 | f:write("x") | ||
584 | assert(fr:read("all") == "") -- full buffer; output not written yet | ||
585 | f:close() | ||
586 | fr:seek("set") | ||
587 | assert(fr:read("all") == "x") -- `close' flushes it | ||
588 | f = assert(io.open(file), "w") | ||
589 | assert(f:setvbuf("no")) | ||
590 | f:write("x") | ||
591 | fr:seek("set") | ||
592 | assert(fr:read("all") == "x") -- no buffer; output is ready | ||
593 | f:close() | ||
594 | f = assert(io.open(file, "a")) | ||
595 | assert(f:setvbuf("line")) | ||
596 | f:write("x") | ||
597 | fr:seek("set", 1) | ||
598 | assert(fr:read("all") == "") -- line buffer; no output without `\n' | ||
599 | f:write("a\n"):seek("set", 1) | ||
600 | assert(fr:read("all") == "xa\n") -- now we have a whole line | ||
601 | f:close(); fr:close() | ||
602 | assert(os.remove(file)) | ||
603 | end | ||
604 | |||
605 | |||
606 | if not _soft then | ||
607 | print("testing large files (> BUFSIZ)") | ||
608 | io.output(file) | ||
609 | for i=1,5001 do io.write('0123456789123') end | ||
610 | io.write('\n12346'):close() | ||
611 | io.input(file) | ||
612 | local x = io.read('a') | ||
613 | io.input():seek('set', 0) | ||
614 | local y = io.read(30001)..io.read(1005)..io.read(0).. | ||
615 | io.read(1)..io.read(100003) | ||
616 | assert(x == y and string.len(x) == 5001*13 + 6) | ||
617 | io.input():seek('set', 0) | ||
618 | y = io.read() -- huge line | ||
619 | assert(x == y..'\n'..io.read()) | ||
620 | assert(io.read() == nil) | ||
621 | io.close(io.input()) | ||
622 | assert(os.remove(file)) | ||
623 | x = nil; y = nil | ||
624 | end | ||
625 | |||
626 | if not _port then | ||
627 | local progname | ||
628 | do -- get name of running executable | ||
629 | local arg = arg or _ARG | ||
630 | local i = 0 | ||
631 | while arg[i] do i = i - 1 end | ||
632 | progname = '"' .. arg[i + 1] .. '"' | ||
633 | end | ||
634 | print("testing popen/pclose and execute") | ||
635 | local tests = { | ||
636 | -- command, what, code | ||
637 | {"ls > /dev/null", "ok"}, | ||
638 | {"not-to-be-found-command", "exit"}, | ||
639 | {"exit 3", "exit", 3}, | ||
640 | {"exit 129", "exit", 129}, | ||
641 | {"kill -s HUP $$", "signal", 1}, | ||
642 | {"kill -s KILL $$", "signal", 9}, | ||
643 | {"sh -c 'kill -s HUP $$'", "exit"}, | ||
644 | {progname .. ' -e " "', "ok"}, | ||
645 | {progname .. ' -e "os.exit(0, true)"', "ok"}, | ||
646 | {progname .. ' -e "os.exit(20, true)"', "exit", 20}, | ||
647 | } | ||
648 | print("\n(some error messages are expected now)") | ||
649 | for _, v in ipairs(tests) do | ||
650 | local x, y, z = io.popen(v[1]):close() | ||
651 | local x1, y1, z1 = os.execute(v[1]) | ||
652 | assert(x == x1 and y == y1 and z == z1) | ||
653 | if v[2] == "ok" then | ||
654 | assert(x and y == 'exit' and z == 0) | ||
655 | else | ||
656 | assert(not x and y == v[2]) -- correct status and 'what' | ||
657 | -- correct code if known (but always different from 0) | ||
658 | assert((v[3] == nil and z > 0) or v[3] == z) | ||
659 | end | ||
660 | end | ||
661 | end | ||
662 | |||
663 | |||
664 | -- testing tmpfile | ||
665 | f = io.tmpfile() | ||
666 | assert(io.type(f) == "file") | ||
667 | f:write("alo") | ||
668 | f:seek("set") | ||
669 | assert(f:read"a" == "alo") | ||
670 | |||
671 | end --} | ||
672 | |||
673 | print'+' | ||
674 | |||
675 | print("testing date/time") | ||
676 | |||
677 | assert(os.date("") == "") | ||
678 | assert(os.date("!") == "") | ||
679 | assert(os.date("\0\0") == "\0\0") | ||
680 | assert(os.date("!\0\0") == "\0\0") | ||
681 | local x = string.rep("a", 10000) | ||
682 | assert(os.date(x) == x) | ||
683 | local t = os.time() | ||
684 | D = os.date("*t", t) | ||
685 | assert(os.date(string.rep("%d", 1000), t) == | ||
686 | string.rep(os.date("%d", t), 1000)) | ||
687 | assert(os.date(string.rep("%", 200)) == string.rep("%", 100)) | ||
688 | |||
689 | local t = os.time() | ||
690 | D = os.date("*t", t) | ||
691 | load(os.date([[assert(D.year==%Y and D.month==%m and D.day==%d and | ||
692 | D.hour==%H and D.min==%M and D.sec==%S and | ||
693 | D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))() | ||
694 | |||
695 | checkerr("invalid conversion specifier", os.date, "%") | ||
696 | checkerr("invalid conversion specifier", os.date, "%9") | ||
697 | checkerr("invalid conversion specifier", os.date, "%") | ||
698 | checkerr("invalid conversion specifier", os.date, "%O") | ||
699 | checkerr("invalid conversion specifier", os.date, "%E") | ||
700 | checkerr("invalid conversion specifier", os.date, "%Ea") | ||
701 | |||
702 | checkerr("not an integer", os.time, {year=1000, month=1, day=1, hour='x'}) | ||
703 | checkerr("not an integer", os.time, {year=1000, month=1, day=1, hour=1.5}) | ||
704 | |||
705 | checkerr("missing", os.time, {hour = 12}) -- missing date | ||
706 | |||
707 | if not _port then | ||
708 | -- test Posix-specific modifiers | ||
709 | assert(type(os.date("%Ex")) == 'string') | ||
710 | assert(type(os.date("%Oy")) == 'string') | ||
711 | |||
712 | |||
713 | -- test out-of-range dates (at least for Unix) | ||
714 | if maxint >= 2^62 then -- cannot do these tests in Small Lua | ||
715 | -- no arith overflows | ||
716 | checkerr("out-of-bound", os.time, {year = -maxint, month = 1, day = 1}) | ||
717 | if string.packsize("i") == 4 then -- 4-byte ints | ||
718 | if testerr("out-of-bound", os.date, "%Y", 2^40) then | ||
719 | -- time_t has 4 bytes and therefore cannot represent year 4000 | ||
720 | print(" 4-byte time_t") | ||
721 | checkerr("cannot be represented", os.time, {year=4000, month=1, day=1}) | ||
722 | else | ||
723 | -- time_t has 8 bytes; an int year cannot represent a huge time | ||
724 | print(" 8-byte time_t") | ||
725 | checkerr("cannot be represented", os.date, "%Y", 2^60) | ||
726 | -- it should have no problems with year 4000 | ||
727 | assert(tonumber(os.time{year=4000, month=1, day=1})) | ||
728 | end | ||
729 | else -- 8-byte ints | ||
730 | -- assume time_t has 8 bytes too | ||
731 | print(" 8-byte time_t") | ||
732 | assert(tonumber(os.date("%Y", 2^60))) | ||
733 | -- but still cannot represent a huge year | ||
734 | checkerr("cannot be represented", os.time, {year=2^60, month=1, day=1}) | ||
735 | end | ||
736 | end | ||
737 | end | ||
738 | |||
739 | |||
740 | D = os.date("!*t", t) | ||
741 | load(os.date([[!assert(D.year==%Y and D.month==%m and D.day==%d and | ||
742 | D.hour==%H and D.min==%M and D.sec==%S and | ||
743 | D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))() | ||
744 | |||
745 | do | ||
746 | local D = os.date("*t") | ||
747 | local t = os.time(D) | ||
748 | assert(type(D.isdst) == 'boolean') | ||
749 | D.isdst = nil | ||
750 | local t1 = os.time(D) | ||
751 | assert(t == t1) -- if isdst is absent uses correct default | ||
752 | end | ||
753 | |||
754 | t = os.time(D) | ||
755 | D.year = D.year-1; | ||
756 | local t1 = os.time(D) | ||
757 | -- allow for leap years | ||
758 | assert(math.abs(os.difftime(t,t1)/(24*3600) - 365) < 2) | ||
759 | |||
760 | -- should not take more than 1 second to execute these two lines | ||
761 | t = os.time() | ||
762 | t1 = os.time(os.date("*t")) | ||
763 | local diff = os.difftime(t1,t) | ||
764 | assert(0 <= diff and diff <= 1) | ||
765 | diff = os.difftime(t,t1) | ||
766 | assert(-1 <= diff and diff <= 0) | ||
767 | |||
768 | local t1 = os.time{year=2000, month=10, day=1, hour=23, min=12} | ||
769 | local t2 = os.time{year=2000, month=10, day=1, hour=23, min=10, sec=19} | ||
770 | assert(os.difftime(t1,t2) == 60*2-19) | ||
771 | |||
772 | -- since 5.3.3, 'os.time' normalizes table fields | ||
773 | t1 = {year = 2005, month = 1, day = 1, hour = 1, min = 0, sec = -3602} | ||
774 | os.time(t1) | ||
775 | assert(t1.day == 31 and t1.month == 12 and t1.year == 2004 and | ||
776 | t1.hour == 23 and t1.min == 59 and t1.sec == 58 and | ||
777 | t1.yday == 366) | ||
778 | |||
779 | io.output(io.stdout) | ||
780 | local t = os.date('%d %m %Y %H %M %S') | ||
781 | local d, m, a, h, min, s = string.match(t, | ||
782 | "(%d+) (%d+) (%d+) (%d+) (%d+) (%d+)") | ||
783 | d = tonumber(d) | ||
784 | m = tonumber(m) | ||
785 | a = tonumber(a) | ||
786 | h = tonumber(h) | ||
787 | min = tonumber(min) | ||
788 | s = tonumber(s) | ||
789 | io.write(string.format('test done on %2.2d/%2.2d/%d', d, m, a)) | ||
790 | io.write(string.format(', at %2.2d:%2.2d:%2.2d\n', h, min, s)) | ||
791 | io.write(string.format('%s\n', _VERSION)) | ||
792 | |||
793 | |||