files.lua 27 KB

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