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