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