2
0

files.lua 22 KB

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