summaryrefslogtreecommitdiff
path: root/testes/files.lua
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-17 14:46:37 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-17 14:46:37 -0200
commit063d4e4543088e7a21965bda8ee5a0f952a9029e (patch)
tree6c3f2f8e98c26f071a94a32f9f2754396a66a9de /testes/files.lua
parente354c6355e7f48e087678ec49e340ca0696725b1 (diff)
downloadlua-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/files.lua')
-rw-r--r--testes/files.lua793
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
4local debug = require "debug"
5
6local maxint = math.maxinteger
7
8assert(type(os.getenv"PATH") == "string")
9
10assert(io.input(io.stdin) == io.stdin)
11assert(not pcall(io.input, "non-existent-file"))
12assert(io.output(io.stdout) == io.stdout)
13
14
15local function testerr (msg, f, ...)
16 local stat, err = pcall(f, ...)
17 return (not stat and string.find(err, msg, 1, true))
18end
19
20
21local function checkerr (msg, f, ...)
22 assert(testerr(msg, f, ...))
23end
24
25
26-- cannot close standard files
27assert(not io.close(io.stdin) and
28 not io.stdout:close() and
29 not io.stderr:close())
30
31
32assert(type(io.input()) == "userdata" and io.type(io.output()) == "file")
33assert(type(io.stdin) == "userdata" and io.type(io.stderr) == "file")
34assert(not io.type(8))
35local a = {}; setmetatable(a, {})
36assert(not io.type(a))
37
38assert(getmetatable(io.input()).__name == "FILE*")
39
40local a,b,c = io.open('xuxu_nao_existe')
41assert(not a and type(b) == "string" and type(c) == "number")
42
43a,b,c = io.open('/a/b/c/d', 'w')
44assert(not a and type(b) == "string" and type(c) == "number")
45
46local file = os.tmpname()
47local f, msg = io.open(file, "w")
48if not f then
49 (Message or print)("'os.tmpname' file cannot be open; skipping file tests")
50
51else --{ most tests here need tmpname
52f:close()
53
54print('testing i/o')
55
56local otherfile = os.tmpname()
57
58checkerr("invalid mode", io.open, file, "rw")
59checkerr("invalid mode", io.open, file, "rb+")
60checkerr("invalid mode", io.open, file, "r+bk")
61checkerr("invalid mode", io.open, file, "")
62checkerr("invalid mode", io.open, file, "+")
63checkerr("invalid mode", io.open, file, "b")
64assert(io.open(file, "r+b")):close()
65assert(io.open(file, "r+")):close()
66assert(io.open(file, "rb")):close()
67
68assert(os.setlocale('C', 'all'))
69
70io.input(io.stdin); io.output(io.stdout);
71
72os.remove(file)
73assert(not loadfile(file))
74checkerr("", dofile, file)
75assert(not io.open(file))
76io.output(file)
77assert(io.output() ~= io.stdout)
78
79if 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")
82end
83
84assert(io.output():seek() == 0)
85assert(io.write("alo alo"):seek() == string.len("alo alo"))
86assert(io.output():seek("cur", -3) == string.len("alo alo")-3)
87assert(io.write("joao"))
88assert(io.output():seek("end") == string.len("alo joao"))
89
90assert(io.output():seek("set") == 0)
91
92assert(io.write('"álo"', "{a}\n", "second line\n", "third line \n"))
93assert(io.write('çfourth_line'))
94io.output(io.stdout)
95collectgarbage() -- file should be closed by GC
96assert(io.input() == io.stdin and rawequal(io.output(), io.stdout))
97print('+')
98
99-- test GC for files
100collectgarbage()
101for 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()
108end
109
110io.input():close()
111io.close()
112
113assert(os.rename(file, otherfile))
114assert(not os.rename(file, otherfile))
115
116io.output(io.open(otherfile, "ab"))
117assert(io.write("\n\n\t\t ", 3450, "\n"));
118io.close()
119
120-- test writing/reading numbers
121f = assert(io.open(file, "w"))
122f:write(maxint, '\n')
123f:write(string.format("0X%x\n", maxint))
124f:write("0xABCp-3", '\n')
125f:write(0, '\n')
126f:write(-maxint, '\n')
127f:write(string.format("0x%X\n", -maxint))
128f:write("-0xABCp-3", '\n')
129assert(f:close())
130f = assert(io.open(file, "r"))
131assert(f:read("n") == maxint)
132assert(f:read("n") == maxint)
133assert(f:read("n") == 0xABCp-3)
134assert(f:read("n") == 0)
135assert(f:read("*n") == -maxint) -- test old format (with '*')
136assert(f:read("n") == -maxint)
137assert(f:read("*n") == -0xABCp-3) -- test old format (with '*')
138assert(f:close())
139assert(os.remove(file))
140
141-- test yielding during 'dofile'
142f = assert(io.open(file, "w"))
143f:write[[
144local x, z = coroutine.yield(10)
145local y = coroutine.yield(20)
146return x + y * z
147]]
148assert(f:close())
149f = coroutine.wrap(dofile)
150assert(f(file) == 10)
151print(f(100, 101) == 20)
152assert(f(200) == 100 + 200 * 101)
153assert(os.remove(file))
154
155
156f = assert(io.open(file, "w"))
157-- test number termination
158f:write[[
159-12.3- -0xffff+ .3|5.E-3X +234e+13E 0xDEADBEEFDEADBEEFx
1600x1.13Ap+3e
161]]
162-- very long number
163f:write("1234"); for i = 1, 1000 do f:write("0") end; f:write("\n")
164-- invalid sequences (must read and discard valid prefixes)
165f:write[[
166.e+ 0.e; --; 0xX;
167]]
168assert(f:close())
169f = assert(io.open(file, "r"))
170assert(f:read("n") == -12.3); assert(f:read(1) == "-")
171assert(f:read("n") == -0xffff); assert(f:read(2) == "+ ")
172assert(f:read("n") == 0.3); assert(f:read(1) == "|")
173assert(f:read("n") == 5e-3); assert(f:read(1) == "X")
174assert(f:read("n") == 234e13); assert(f:read(1) == "E")
175assert(f:read("n") == 0Xdeadbeefdeadbeef); assert(f:read(2) == "x\n")
176assert(f:read("n") == 0x1.13aP3); assert(f:read(1) == "e")
177
178do -- 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
182end
183
184assert(not f:read("n")); assert(f:read(2) == "e+")
185assert(not f:read("n")); assert(f:read(1) == ";")
186assert(not f:read("n")); assert(f:read(2) == "-;")
187assert(not f:read("n")); assert(f:read(1) == "X")
188assert(not f:read("n")); assert(f:read(1) == ";")
189assert(not f:read("n")); assert(not f:read(0)) -- end of file
190assert(f:close())
191assert(os.remove(file))
192
193
194-- test line generators
195assert(not pcall(io.lines, "non-existent-file"))
196assert(os.rename(otherfile, file))
197io.output(otherfile)
198local n = 0
199local f = io.lines(file)
200while f() do n = n + 1 end;
201assert(n == 6) -- number of lines in the file
202checkerr("file is already closed", f)
203checkerr("file is already closed", f)
204-- copy from file to otherfile
205n = 0
206for l in io.lines(file) do io.write(l, "\n"); n = n + 1 end
207io.close()
208assert(n == 6)
209-- copy from otherfile back to file
210local f = assert(io.open(otherfile))
211assert(io.type(f) == "file")
212io.output(file)
213assert(not io.output():read())
214n = 0
215for l in f:lines() do io.write(l, "\n"); n = n + 1 end
216assert(tostring(f):sub(1, 5) == "file ")
217assert(f:close()); io.close()
218assert(n == 6)
219checkerr("closed file", io.close, f)
220assert(tostring(f) == "file (closed)")
221assert(io.type(f) == "closed file")
222io.input(file)
223f = io.open(otherfile):lines()
224n = 0
225for l in io.lines() do assert(l == f()); n = n + 1 end
226f = nil; collectgarbage()
227assert(n == 6)
228assert(os.remove(otherfile))
229
230do -- 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))
242end
243
244io.input(file)
245do -- test error returns
246 local a,b,c = io.input():write("xuxu")
247 assert(not a and type(b) == "string" and type(c) == "number")
248end
249checkerr("invalid format", io.read, "x")
250assert(io.read(0) == "") -- not eof
251assert(io.read(5, 'l') == '"álo"')
252assert(io.read(0) == "")
253assert(io.read() == "second line")
254local x = io.input():seek()
255assert(io.read() == "third line ")
256assert(io.input():seek("set", x))
257assert(io.read('L') == "third line \n")
258assert(io.read(1) == "ç")
259assert(io.read(string.len"fourth_line") == "fourth_line")
260assert(io.input():seek("cur", -string.len"fourth_line"))
261assert(io.read() == "fourth_line")
262assert(io.read() == "") -- empty line
263assert(io.read('n') == 3450)
264assert(io.read(1) == '\n')
265assert(io.read(0) == nil) -- end of file
266assert(io.read(1) == nil) -- end of file
267assert(io.read(30000) == nil) -- end of file
268assert(({io.read(1)})[2] == nil)
269assert(io.read() == nil) -- end of file
270assert(({io.read()})[2] == nil)
271assert(io.read('n') == nil) -- end of file
272assert(({io.read('n')})[2] == nil)
273assert(io.read('a') == '') -- end of file (OK for 'a')
274assert(io.read('a') == '') -- end of file (OK for 'a')
275collectgarbage()
276print('+')
277io.close(io.input())
278checkerr(" input file is closed", io.read)
279
280assert(os.remove(file))
281
282local t = '0123456789'
283for i=1,10 do t = t..t; end
284assert(string.len(t) == 10*2^10)
285
286io.output(file)
287io.write("alo"):write("\n")
288io.close()
289checkerr(" output file is closed", io.write)
290local f = io.open(file, "a+b")
291io.output(f)
292collectgarbage()
293
294assert(io.write(' ' .. t .. ' '))
295assert(io.write(';', 'end of file\n'))
296f:flush(); io.flush()
297f:close()
298print('+')
299
300io.input(file)
301assert(io.read() == "alo")
302assert(io.read(1) == ' ')
303assert(io.read(string.len(t)) == t)
304assert(io.read(1) == ' ')
305assert(io.read(0))
306assert(io.read('a') == ';end of file\n')
307assert(io.read(0) == nil)
308assert(io.close(io.input()))
309
310
311-- test errors in read/write
312do
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())
333end
334
335assert(os.remove(file))
336
337-- test for L format
338io.output(file); io.write"\n\nline\nother":close()
339io.input(file)
340assert(io.read"L" == "\n")
341assert(io.read"L" == "\n")
342assert(io.read"L" == "line\n")
343assert(io.read"L" == "other")
344assert(io.read"L" == nil)
345io.input():close()
346
347local f = assert(io.open(file))
348local s = ""
349for l in f:lines("L") do s = s .. l end
350assert(s == "\n\nline\nother")
351f:close()
352
353io.input(file)
354s = ""
355for l in io.lines(nil, "L") do s = s .. l end
356assert(s == "\n\nline\nother")
357io.input():close()
358
359s = ""
360for l in io.lines(file, "L") do s = s .. l end
361assert(s == "\n\nline\nother")
362
363s = ""
364for l in io.lines(file, "l") do s = s .. l end
365assert(s == "lineother")
366
367io.output(file); io.write"a = 10 + 34\na = 2*a\na = -a\n":close()
368local t = {}
369load(io.lines(file, "L"), nil, nil, t)()
370assert(t.a == -((10 + 34) * 2))
371
372
373-- test for multipe arguments in 'lines'
374io.output(file); io.write"0123456789\n":close()
375for 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
379end
380
381for a,b,c in io.lines(file, 1, 2, "a") do
382 assert(a == "0" and b == "12" and c == "3456789\n")
383end
384
385for 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)
388end
389collectgarbage() -- to close file in previous iteration
390
391io.output(file); io.write"00\n10\n20\n30\n40\n":close()
392for 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
396end
397
398
399-- test load x lines
400io.output(file);
401io.write[[
402local y
403= X
404X =
405X *
4062 +
407X;
408X =
409X
410- y;
411]]:close()
412_G.X = 1
413assert(not load(io.lines(file)))
414collectgarbage() -- to close file in previous iteration
415load(io.lines(file, "L"))()
416assert(_G.X == 2)
417load(io.lines(file, 1))()
418assert(_G.X == 4)
419load(io.lines(file, 3))()
420assert(_G.X == 8)
421
422print('+')
423
424local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
425io.output(file)
426assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1)))
427io.close()
428assert(loadfile(file))()
429assert(x1 == x2)
430print('+')
431assert(os.remove(file))
432assert(not os.remove(file))
433assert(not os.remove(otherfile))
434
435-- testing loadfile
436local 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)
443end
444
445-- loading empty file
446testloadfile(nil, nil)
447
448-- loading file with initial comment without end of line
449testloadfile("# a non-ending comment", nil)
450
451
452-- checking Unicode BOM in files
453testloadfile("\xEF\xBB\xBF# some comment\nreturn 234", 234)
454testloadfile("\xEF\xBB\xBFreturn 239", 239)
455testloadfile("\xEF\xBB\xBF", nil) -- empty file with a BOM
456
457
458-- checking line numbers in files with initial comments
459testloadfile("# a comment\nreturn require'debug'.getinfo(1).currentline", 2)
460
461
462-- loading binary file
463io.output(io.open(file, "wb"))
464assert(io.write(string.dump(function () return 10, '\0alo\255', 'hi' end)))
465io.close()
466a, b, c = assert(loadfile(file))()
467assert(a == 10 and b == "\0alo\255" and c == "hi")
468assert(os.remove(file))
469
470-- bug in 5.2.1
471do
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))
479end
480
481-- loading binary file with initial comment
482io.output(io.open(file, "wb"))
483assert(io.write("#this is a comment for a binary file\0\n",
484 string.dump(function () return 20, '\0\0\0' end)))
485io.close()
486a, b, c = assert(loadfile(file))()
487assert(a == 20 and b == "\0\0\0" and c == nil)
488assert(os.remove(file))
489
490
491-- 'loadfile' with 'env'
492do
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))
510end
511
512
513-- 'loadfile' x modes
514do
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))
522end
523
524
525io.output(file)
526assert(io.write("qualquer coisa\n"))
527assert(io.write("mais qualquer coisa"))
528io.close()
529assert(io.output(assert(io.open(otherfile, 'wb')))
530 :write("outra coisa\0\1\3\0\0\0\0\255\0")
531 :close())
532
533local filehandle = assert(io.open(file, 'r+'))
534local otherfilehandle = assert(io.open(otherfile, 'rb'))
535assert(filehandle ~= otherfilehandle)
536assert(type(filehandle) == "userdata")
537assert(filehandle:read('l') == "qualquer coisa")
538io.input(otherfilehandle)
539assert(io.read(string.len"outra coisa") == "outra coisa")
540assert(filehandle:read('l') == "mais qualquer coisa")
541filehandle:close();
542assert(type(filehandle) == "userdata")
543io.input(otherfilehandle)
544assert(io.read(4) == "\0\1\3\0")
545assert(io.read(3) == "\0\0\0")
546assert(io.read(0) == "") -- 255 is not eof
547assert(io.read(1) == "\255")
548assert(io.read('a') == "\0")
549assert(not io.read(0))
550assert(otherfilehandle == io.input())
551otherfilehandle:close()
552assert(os.remove(file))
553assert(os.remove(otherfile))
554collectgarbage()
555
556io.output(file)
557 :write[[
558 123.4 -56e-2 not a number
559second line
560third line
561
562and the rest of the file
563]]
564 :close()
565io.input(file)
566local _,a,b,c,d,e,h,__ = io.read(1, 'n', 'n', 'l', 'l', 'l', 'a', 10)
567assert(io.close(io.input()))
568assert(_ == ' ' and __ == nil)
569assert(type(a) == 'number' and a==123.4 and b==-56e-2)
570assert(d=='second line' and e=='third line')
571assert(h==[[
572
573and the rest of the file
574]])
575assert(os.remove(file))
576collectgarbage()
577
578-- testing buffers
579do
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))
603end
604
605
606if 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
624end
625
626if 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
661end
662
663
664-- testing tmpfile
665f = io.tmpfile()
666assert(io.type(f) == "file")
667f:write("alo")
668f:seek("set")
669assert(f:read"a" == "alo")
670
671end --}
672
673print'+'
674
675print("testing date/time")
676
677assert(os.date("") == "")
678assert(os.date("!") == "")
679assert(os.date("\0\0") == "\0\0")
680assert(os.date("!\0\0") == "\0\0")
681local x = string.rep("a", 10000)
682assert(os.date(x) == x)
683local t = os.time()
684D = os.date("*t", t)
685assert(os.date(string.rep("%d", 1000), t) ==
686 string.rep(os.date("%d", t), 1000))
687assert(os.date(string.rep("%", 200)) == string.rep("%", 100))
688
689local t = os.time()
690D = os.date("*t", t)
691load(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
695checkerr("invalid conversion specifier", os.date, "%")
696checkerr("invalid conversion specifier", os.date, "%9")
697checkerr("invalid conversion specifier", os.date, "%")
698checkerr("invalid conversion specifier", os.date, "%O")
699checkerr("invalid conversion specifier", os.date, "%E")
700checkerr("invalid conversion specifier", os.date, "%Ea")
701
702checkerr("not an integer", os.time, {year=1000, month=1, day=1, hour='x'})
703checkerr("not an integer", os.time, {year=1000, month=1, day=1, hour=1.5})
704
705checkerr("missing", os.time, {hour = 12}) -- missing date
706
707if 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
737end
738
739
740D = os.date("!*t", t)
741load(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
745do
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
752end
753
754t = os.time(D)
755D.year = D.year-1;
756local t1 = os.time(D)
757-- allow for leap years
758assert(math.abs(os.difftime(t,t1)/(24*3600) - 365) < 2)
759
760-- should not take more than 1 second to execute these two lines
761t = os.time()
762t1 = os.time(os.date("*t"))
763local diff = os.difftime(t1,t)
764assert(0 <= diff and diff <= 1)
765diff = os.difftime(t,t1)
766assert(-1 <= diff and diff <= 0)
767
768local t1 = os.time{year=2000, month=10, day=1, hour=23, min=12}
769local t2 = os.time{year=2000, month=10, day=1, hour=23, min=10, sec=19}
770assert(os.difftime(t1,t2) == 60*2-19)
771
772-- since 5.3.3, 'os.time' normalizes table fields
773t1 = {year = 2005, month = 1, day = 1, hour = 1, min = 0, sec = -3602}
774os.time(t1)
775assert(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
779io.output(io.stdout)
780local t = os.date('%d %m %Y %H %M %S')
781local d, m, a, h, min, s = string.match(t,
782 "(%d+) (%d+) (%d+) (%d+) (%d+) (%d+)")
783d = tonumber(d)
784m = tonumber(m)
785a = tonumber(a)
786h = tonumber(h)
787min = tonumber(min)
788s = tonumber(s)
789io.write(string.format('test done on %2.2d/%2.2d/%d', d, m, a))
790io.write(string.format(', at %2.2d:%2.2d:%2.2d\n', h, min, s))
791io.write(string.format('%s\n', _VERSION))
792
793