files.lua 27 KB

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