files.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. debug = require "debug"
  2. assert(type(os.getenv"PATH") == "string")
  3. assert(io.input(io.stdin) == io.stdin)
  4. assert(not pcall(io.input, "non-existent-file"))
  5. assert(io.output(io.stdout) == io.stdout)
  6. -- cannot close standard files
  7. assert(not io.close(io.stdin) and
  8. not io.stdout:close() and
  9. not io.stderr:close())
  10. assert(type(io.input()) == "userdata" and io.type(io.output()) == "file")
  11. assert(type(io.stdin) == "userdata" and io.type(io.stderr) == "file")
  12. assert(io.type(8) == nil)
  13. local a = {}; setmetatable(a, {})
  14. assert(io.type(a) == nil)
  15. local a,b,c = io.open('xuxu_nao_existe')
  16. assert(not a and type(b) == "string" and type(c) == "number")
  17. a,b,c = io.open('/a/b/c/d', 'w')
  18. assert(not a and type(b) == "string" and type(c) == "number")
  19. local file = os.tmpname()
  20. local f, msg = io.open(file, "w")
  21. if not f then
  22. (Message or print)("'os.tmpname' file cannot be open; skipping file tests")
  23. else --{ most tests here need tmpname
  24. f:close()
  25. print('testing i/o')
  26. local otherfile = os.tmpname()
  27. assert(not pcall(io.open, file, "rw")) -- invalid mode
  28. assert(not pcall(io.open, file, "rb+")) -- invalid mode
  29. assert(not pcall(io.open, file, "r+bk")) -- invalid mode
  30. assert(not pcall(io.open, file, "")) -- invalid mode
  31. assert(not pcall(io.open, file, "+")) -- invalid mode
  32. assert(not pcall(io.open, file, "b")) -- invalid mode
  33. assert(io.open(file, "r+b")):close()
  34. assert(io.open(file, "r+")):close()
  35. assert(io.open(file, "rb")):close()
  36. assert(os.setlocale('C', 'all'))
  37. io.input(io.stdin); io.output(io.stdout);
  38. os.remove(file)
  39. assert(loadfile(file) == nil)
  40. assert(io.open(file) == nil)
  41. io.output(file)
  42. assert(io.output() ~= io.stdout)
  43. assert(io.output():seek() == 0)
  44. assert(io.write("alo alo"):seek() == string.len("alo alo"))
  45. assert(io.output():seek("cur", -3) == string.len("alo alo")-3)
  46. assert(io.write("joao"))
  47. assert(io.output():seek("end") == string.len("alo joao"))
  48. assert(io.output():seek("set") == 0)
  49. assert(io.write('"álo"', "{a}\n", "second line\n", "third line \n"))
  50. assert(io.write('çfourth_line'))
  51. io.output(io.stdout)
  52. collectgarbage() -- file should be closed by GC
  53. assert(io.input() == io.stdin and rawequal(io.output(), io.stdout))
  54. print('+')
  55. -- test GC for files
  56. collectgarbage()
  57. for i=1,120 do
  58. for i=1,5 do
  59. io.input(file)
  60. assert(io.open(file, 'r'))
  61. io.lines(file)
  62. end
  63. collectgarbage()
  64. end
  65. io.input():close()
  66. io.close()
  67. assert(os.rename(file, otherfile))
  68. assert(os.rename(file, otherfile) == nil)
  69. io.output(io.open(otherfile, "ab"))
  70. assert(io.write("\n\n\t\t 3450\n"));
  71. io.close()
  72. -- test line generators
  73. assert(not pcall(io.lines, "non-existent-file"))
  74. assert(os.rename(otherfile, file))
  75. io.output(otherfile)
  76. local f = io.lines(file)
  77. while f() do end;
  78. assert(not pcall(f)) -- read lines after EOF
  79. assert(not pcall(f)) -- read lines after EOF
  80. -- copy from file to otherfile
  81. for l in io.lines(file) do io.write(l, "\n") end
  82. io.close()
  83. -- copy from otherfile back to file
  84. local f = assert(io.open(otherfile))
  85. assert(io.type(f) == "file")
  86. io.output(file)
  87. assert(io.output():read() == nil)
  88. for l in f:lines() do io.write(l, "\n") end
  89. assert(tostring(f):sub(1, 5) == "file ")
  90. assert(f:close()); io.close()
  91. assert(not pcall(io.close, f)) -- error trying to close again
  92. assert(tostring(f) == "file (closed)")
  93. assert(io.type(f) == "closed file")
  94. io.input(file)
  95. f = io.open(otherfile):lines()
  96. for l in io.lines() do assert(l == f()) end
  97. f = nil; collectgarbage()
  98. assert(os.remove(otherfile))
  99. io.input(file)
  100. do -- test error returns
  101. local a,b,c = io.input():write("xuxu")
  102. assert(not a and type(b) == "string" and type(c) == "number")
  103. end
  104. assert(io.read(0) == "") -- not eof
  105. assert(io.read(5, '*l') == '"álo"')
  106. assert(io.read(0) == "")
  107. assert(io.read() == "second line")
  108. local x = io.input():seek()
  109. assert(io.read() == "third line ")
  110. assert(io.input():seek("set", x))
  111. assert(io.read('*L') == "third line \n")
  112. assert(io.read(1) == "ç")
  113. assert(io.read(string.len"fourth_line") == "fourth_line")
  114. assert(io.input():seek("cur", -string.len"fourth_line"))
  115. assert(io.read() == "fourth_line")
  116. assert(io.read() == "") -- empty line
  117. assert(io.read('*n') == 3450)
  118. assert(io.read(1) == '\n')
  119. assert(io.read(0) == nil) -- end of file
  120. assert(io.read(1) == nil) -- end of file
  121. assert(io.read(30000) == nil) -- end of file
  122. assert(({io.read(1)})[2] == nil)
  123. assert(io.read() == nil) -- end of file
  124. assert(({io.read()})[2] == nil)
  125. assert(io.read('*n') == nil) -- end of file
  126. assert(({io.read('*n')})[2] == nil)
  127. assert(io.read('*a') == '') -- end of file (OK for `*a')
  128. assert(io.read('*a') == '') -- end of file (OK for `*a')
  129. collectgarbage()
  130. print('+')
  131. io.close(io.input())
  132. assert(not pcall(io.read))
  133. assert(os.remove(file))
  134. local t = '0123456789'
  135. for i=1,12 do t = t..t; end
  136. assert(string.len(t) == 10*2^12)
  137. io.output(file)
  138. io.write("alo"):write("\n")
  139. io.close()
  140. assert(not pcall(io.write))
  141. local f = io.open(file, "a+b")
  142. io.output(f)
  143. collectgarbage()
  144. assert(io.write(' ' .. t .. ' '))
  145. assert(io.write(';', 'end of file\n'))
  146. f:flush(); io.flush()
  147. f:close()
  148. print('+')
  149. io.input(file)
  150. assert(io.read() == "alo")
  151. assert(io.read(1) == ' ')
  152. assert(io.read(string.len(t)) == t)
  153. assert(io.read(1) == ' ')
  154. assert(io.read(0))
  155. assert(io.read('*a') == ';end of file\n')
  156. assert(io.read(0) == nil)
  157. assert(io.close(io.input()))
  158. -- test errors in read/write
  159. do
  160. local function ismsg (m)
  161. -- error message is not a code number
  162. return (type(m) == "string" and tonumber(m) == nil)
  163. end
  164. -- read
  165. local f = io.open(file, "w")
  166. local r, m, c = f:read()
  167. assert(r == nil and ismsg(m) and type(c) == "number")
  168. assert(f:close())
  169. -- write
  170. f = io.open(file, "r")
  171. r, m, c = f:write("whatever")
  172. assert(r == nil and ismsg(m) and type(c) == "number")
  173. assert(f:close())
  174. -- lines
  175. f = io.open(file, "w")
  176. r, m = pcall(f:lines())
  177. assert(r == false and ismsg(m))
  178. assert(f:close())
  179. end
  180. assert(os.remove(file))
  181. -- test for *L format
  182. io.output(file); io.write"\n\nline\nother":close()
  183. io.input(file)
  184. assert(io.read"*L" == "\n")
  185. assert(io.read"*L" == "\n")
  186. assert(io.read"*L" == "line\n")
  187. assert(io.read"*L" == "other")
  188. assert(io.read"*L" == nil)
  189. io.input():close()
  190. local f = assert(io.open(file))
  191. local s = ""
  192. for l in f:lines("*L") do s = s .. l end
  193. assert(s == "\n\nline\nother")
  194. f:close()
  195. io.input(file)
  196. s = ""
  197. for l in io.lines(nil, "*L") do s = s .. l end
  198. assert(s == "\n\nline\nother")
  199. io.input():close()
  200. s = ""
  201. for l in io.lines(file, "*L") do s = s .. l end
  202. assert(s == "\n\nline\nother")
  203. s = ""
  204. for l in io.lines(file, "*l") do s = s .. l end
  205. assert(s == "lineother")
  206. io.output(file); io.write"a = 10 + 34\na = 2*a\na = -a\n":close()
  207. local t = {}
  208. load(io.lines(file, "*L"), nil, nil, t)()
  209. assert(t.a == -((10 + 34) * 2))
  210. -- test for multipe arguments in 'lines'
  211. io.output(file); io.write"0123456789\n":close()
  212. for a,b in io.lines(file, 1, 1) do
  213. if a == "\n" then assert(b == nil)
  214. else assert(tonumber(a) == b - 1)
  215. end
  216. end
  217. for a,b,c in io.lines(file, 1, 2, "*a") do
  218. assert(a == "0" and b == "12" and c == "3456789\n")
  219. end
  220. for a,b,c in io.lines(file, "*a", 0, 1) do
  221. if a == "" then break end
  222. assert(a == "0123456789\n" and b == nil and c == nil)
  223. end
  224. collectgarbage() -- to close file in previous iteration
  225. io.output(file); io.write"00\n10\n20\n30\n40\n":close()
  226. for a, b in io.lines(file, "*n", "*n") do
  227. if a == 40 then assert(b == nil)
  228. else assert(a == b - 10)
  229. end
  230. end
  231. -- test load x lines
  232. io.output(file);
  233. io.write[[
  234. local y
  235. = X
  236. X =
  237. X *
  238. 2 +
  239. X;
  240. X =
  241. X
  242. - y;
  243. ]]:close()
  244. _G.X = 1
  245. assert(not load(io.lines(file)))
  246. collectgarbage() -- to close file in previous iteration
  247. load(io.lines(file, "*L"))()
  248. assert(_G.X == 2)
  249. load(io.lines(file, 1))()
  250. assert(_G.X == 4)
  251. load(io.lines(file, 3))()
  252. assert(_G.X == 8)
  253. print('+')
  254. local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
  255. io.output(file)
  256. assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1)))
  257. io.close()
  258. assert(loadfile(file))()
  259. assert(x1 == x2)
  260. print('+')
  261. assert(os.remove(file))
  262. assert(os.remove(file) == nil)
  263. assert(os.remove(otherfile) == nil)
  264. -- testing loadfile
  265. local function testloadfile (s, expres)
  266. io.output(file)
  267. if s then io.write(s) end
  268. io.close()
  269. local res = assert(loadfile(file))()
  270. assert(os.remove(file))
  271. assert(res == expres)
  272. end
  273. -- loading empty file
  274. testloadfile(nil, nil)
  275. -- loading file with initial comment without end of line
  276. testloadfile("# a non-ending comment", nil)
  277. -- checking Unicode BOM in files
  278. testloadfile("\xEF\xBB\xBF# some comment\nreturn 234", 234)
  279. testloadfile("\xEF\xBB\xBFreturn 239", 239)
  280. testloadfile("\xEF\xBB\xBF", nil) -- empty file with a BOM
  281. -- checking line numbers in files with initial comments
  282. testloadfile("# a comment\nreturn debug.getinfo(1).currentline", 2)
  283. -- loading binary file
  284. io.output(io.open(file, "wb"))
  285. assert(io.write(string.dump(function () return 10, '\0alo\255', 'hi' end)))
  286. io.close()
  287. a, b, c = assert(loadfile(file))()
  288. assert(a == 10 and b == "\0alo\255" and c == "hi")
  289. assert(os.remove(file))
  290. -- bug in 5.2.1
  291. do
  292. io.output(io.open(file, "wb"))
  293. -- save function with no upvalues
  294. assert(io.write(string.dump(function () return 1 end)))
  295. io.close()
  296. f = assert(loadfile(file, "b", {}))
  297. assert(type(f) == "function" and f() == 1)
  298. assert(os.remove(file))
  299. end
  300. -- loading binary file with initial comment
  301. io.output(io.open(file, "wb"))
  302. assert(io.write("#this is a comment for a binary file\0\n",
  303. string.dump(function () return 20, '\0\0\0' end)))
  304. io.close()
  305. a, b, c = assert(loadfile(file))()
  306. assert(a == 20 and b == "\0\0\0" and c == nil)
  307. assert(os.remove(file))
  308. -- 'loadfile' with 'env'
  309. do
  310. local f = io.open(file, 'w')
  311. f:write[[
  312. if (...) then a = 15; return b, c, d
  313. else return _ENV
  314. end
  315. ]]
  316. f:close()
  317. local t = {b = 12, c = "xuxu", d = print}
  318. local f = assert(loadfile(file, 't', t))
  319. local b, c, d = f(1)
  320. assert(t.a == 15 and b == 12 and c == t.c and d == print)
  321. assert(f() == t)
  322. f = assert(loadfile(file, 't', nil))
  323. assert(f() == nil)
  324. f = assert(loadfile(file))
  325. assert(f() == _G)
  326. assert(os.remove(file))
  327. end
  328. -- 'loadfile' x modes
  329. do
  330. io.open(file, 'w'):write("return 10"):close()
  331. local s, m = loadfile(file, 'b')
  332. assert(not s and string.find(m, "a text chunk"))
  333. io.open(file, 'w'):write("\27 return 10"):close()
  334. local s, m = loadfile(file, 't')
  335. assert(not s and string.find(m, "a binary chunk"))
  336. assert(os.remove(file))
  337. end
  338. io.output(file)
  339. assert(io.write("qualquer coisa\n"))
  340. assert(io.write("mais qualquer coisa"))
  341. io.close()
  342. assert(io.output(assert(io.open(otherfile, 'wb')))
  343. :write("outra coisa\0\1\3\0\0\0\0\255\0")
  344. :close())
  345. local filehandle = assert(io.open(file, 'r+'))
  346. local otherfilehandle = assert(io.open(otherfile, 'rb'))
  347. assert(filehandle ~= otherfilehandle)
  348. assert(type(filehandle) == "userdata")
  349. assert(filehandle:read('*l') == "qualquer coisa")
  350. io.input(otherfilehandle)
  351. assert(io.read(string.len"outra coisa") == "outra coisa")
  352. assert(filehandle:read('*l') == "mais qualquer coisa")
  353. filehandle:close();
  354. assert(type(filehandle) == "userdata")
  355. io.input(otherfilehandle)
  356. assert(io.read(4) == "\0\1\3\0")
  357. assert(io.read(3) == "\0\0\0")
  358. assert(io.read(0) == "") -- 255 is not eof
  359. assert(io.read(1) == "\255")
  360. assert(io.read('*a') == "\0")
  361. assert(not io.read(0))
  362. assert(otherfilehandle == io.input())
  363. otherfilehandle:close()
  364. assert(os.remove(file))
  365. assert(os.remove(otherfile))
  366. collectgarbage()
  367. io.output(file)
  368. :write[[
  369. 123.4 -56e-2 not a number
  370. second line
  371. third line
  372. and the rest of the file
  373. ]]
  374. :close()
  375. io.input(file)
  376. local _,a,b,c,d,e,h,__ = io.read(1, '*n', '*n', '*l', '*l', '*l', '*a', 10)
  377. assert(io.close(io.input()))
  378. assert(_ == ' ' and __ == nil)
  379. assert(type(a) == 'number' and a==123.4 and b==-56e-2)
  380. assert(d=='second line' and e=='third line')
  381. assert(h==[[
  382. and the rest of the file
  383. ]])
  384. assert(os.remove(file))
  385. collectgarbage()
  386. -- testing buffers
  387. do
  388. local f = assert(io.open(file, "w"))
  389. local fr = assert(io.open(file, "r"))
  390. assert(f:setvbuf("full", 2000))
  391. f:write("x")
  392. assert(fr:read("*all") == "") -- full buffer; output not written yet
  393. f:close()
  394. fr:seek("set")
  395. assert(fr:read("*all") == "x") -- `close' flushes it
  396. f = assert(io.open(file), "w")
  397. assert(f:setvbuf("no"))
  398. f:write("x")
  399. fr:seek("set")
  400. assert(fr:read("*all") == "x") -- no buffer; output is ready
  401. f:close()
  402. f = assert(io.open(file, "a"))
  403. assert(f:setvbuf("line"))
  404. f:write("x")
  405. fr:seek("set", 1)
  406. assert(fr:read("*all") == "") -- line buffer; no output without `\n'
  407. f:write("a\n"):seek("set", 1)
  408. assert(fr:read("*all") == "xa\n") -- now we have a whole line
  409. f:close(); fr:close()
  410. assert(os.remove(file))
  411. end
  412. if not _soft then
  413. print("testing large files (> BUFSIZ)")
  414. io.output(file)
  415. for i=1,5001 do io.write('0123456789123') end
  416. io.write('\n12346'):close()
  417. io.input(file)
  418. local x = io.read('*a')
  419. io.input():seek('set', 0)
  420. local y = io.read(30001)..io.read(1005)..io.read(0)..
  421. io.read(1)..io.read(100003)
  422. assert(x == y and string.len(x) == 5001*13 + 6)
  423. io.input():seek('set', 0)
  424. y = io.read() -- huge line
  425. assert(x == y..'\n'..io.read())
  426. assert(io.read() == nil)
  427. io.close(io.input())
  428. assert(os.remove(file))
  429. x = nil; y = nil
  430. end
  431. if not _noposix then
  432. print("testing popen/pclose and execute")
  433. local tests = {
  434. -- command, what, code
  435. {"ls > /dev/null", "ok"},
  436. {"not-to-be-found-command", "exit"},
  437. {"exit 3", "exit", 3},
  438. {"exit 129", "exit", 129},
  439. {"kill -s HUP $$", "signal", 1},
  440. {"kill -s KILL $$", "signal", 9},
  441. {"sh -c 'kill -s HUP $$'", "exit"},
  442. {'lua -e "os.exit(20, true)"', "exit", 20},
  443. }
  444. print("\n(some error messages are expected now)")
  445. for _, v in ipairs(tests) do
  446. local x, y, z = io.popen(v[1]):close()
  447. local x1, y1, z1 = os.execute(v[1])
  448. assert(x == x1 and y == y1 and z == z1)
  449. if v[2] == "ok" then
  450. assert(x == true and y == 'exit' and z == 0)
  451. else
  452. assert(x == nil and y == v[2]) -- correct status and 'what'
  453. -- correct code if known (but always different from 0)
  454. assert((v[3] == nil and z > 0) or v[3] == z)
  455. end
  456. end
  457. end
  458. -- testing tmpfile
  459. f = io.tmpfile()
  460. assert(io.type(f) == "file")
  461. f:write("alo")
  462. f:seek("set")
  463. assert(f:read"*a" == "alo")
  464. end --}
  465. print'+'
  466. assert(os.date("") == "")
  467. assert(os.date("!") == "")
  468. local x = string.rep("a", 10000)
  469. assert(os.date(x) == x)
  470. local t = os.time()
  471. D = os.date("*t", t)
  472. assert(os.date(string.rep("%d", 1000), t) ==
  473. string.rep(os.date("%d", t), 1000))
  474. assert(os.date(string.rep("%", 200)) == string.rep("%", 100))
  475. local t = os.time()
  476. D = os.date("*t", t)
  477. load(os.date([[assert(D.year==%Y and D.month==%m and D.day==%d and
  478. D.hour==%H and D.min==%M and D.sec==%S and
  479. D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))()
  480. assert(not pcall(os.date, "%9")) -- invalid conversion specifier
  481. assert(not pcall(os.date, "%")) -- invalid conversion specifier
  482. assert(not pcall(os.date, "%O")) -- invalid conversion specifier
  483. assert(not pcall(os.date, "%E")) -- invalid conversion specifier
  484. assert(not pcall(os.date, "%Ea")) -- invalid conversion specifier
  485. if not _noposix then
  486. assert(type(os.date("%Ex")) == 'string')
  487. assert(type(os.date("%Oy")) == 'string')
  488. end
  489. assert(os.time(D) == t)
  490. assert(not pcall(os.time, {hour = 12}))
  491. D = os.date("!*t", t)
  492. load(os.date([[!assert(D.year==%Y and D.month==%m and D.day==%d and
  493. D.hour==%H and D.min==%M and D.sec==%S and
  494. D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))()
  495. do
  496. local D = os.date("*t")
  497. local t = os.time(D)
  498. assert(type(D.isdst) == 'boolean')
  499. D.isdst = nil
  500. local t1 = os.time(D)
  501. assert(t == t1) -- if isdst is absent uses correct default
  502. end
  503. t = os.time(D)
  504. D.year = D.year-1;
  505. local t1 = os.time(D)
  506. -- allow for leap years
  507. assert(math.abs(os.difftime(t,t1)/(24*3600) - 365) < 2)
  508. t = os.time()
  509. t1 = os.time(os.date("*t"))
  510. assert(os.difftime(t1,t) <= 2)
  511. local t1 = os.time{year=2000, month=10, day=1, hour=23, min=12}
  512. local t2 = os.time{year=2000, month=10, day=1, hour=23, min=10, sec=19}
  513. assert(os.difftime(t1,t2) == 60*2-19)
  514. io.output(io.stdout)
  515. local d = os.date('%d')
  516. local m = os.date('%m')
  517. local a = os.date('%Y')
  518. local ds = os.date('%w') + 1
  519. local h = os.date('%H')
  520. local min = os.date('%M')
  521. local s = os.date('%S')
  522. io.write(string.format('test done on %2.2d/%2.2d/%d', d, m, a))
  523. io.write(string.format(', at %2.2d:%2.2d:%2.2d\n', h, min, s))
  524. io.write(string.format('%s\n', _VERSION))