CC-Tweaked/src/test/resources/test-rom/spec/apis/io_spec.lua

329 lines
10 KiB
Lua
Raw Blame History

--- Tests the io library is (mostly) consistent with PUC Lua.
--
-- These tests are based on the tests for Lua 5.1 and 5.3
describe("The io library", function()
local file = "/test-files/tmp.txt"
local otherfile = "/test-files/tmp2.txt"
local t = '0123456789'
for _ = 1, 12 do t = t .. t end
assert(#t == 10 * 2 ^ 12)
local function read_all(f)
local h = fs.open(f, "rb")
local contents = h.readAll()
h.close()
return contents
end
local function write_file(f, contents)
local h = fs.open(f, "wb")
h.write(contents)
h.close()
end
local function setup()
write_file(file, "\"<EFBFBD>lo\"{a}\nsecond line\nthird line \n<EFBFBD>fourth_line\n\n\9\9 3450\n")
end
describe("io.close", function()
it("cannot close stdin", function()
expect{ io.stdin:close() }:same { nil, "attempt to close standard stream" }
end)
it("cannot close stdout", function()
expect{ io.stdout:close() }:same { nil, "attempt to close standard stream" }
end)
it("cannot close stdout", function()
expect{ io.stdout:close() }:same { nil, "attempt to close standard stream" }
end)
end)
it("io.input on a handle returns that handle", function()
expect(io.input(io.stdin)):equals(io.stdin)
end)
it("io.output on a handle returns that handle", function()
expect(io.output(io.stdout)):equals(io.stdout)
end)
it("defines a __name field", function()
expect(getmetatable(io.input()).__name):eq("FILE*")
end)
describe("io.type", function()
it("returns file on handles", function()
local handle = io.input()
expect(handle):type("table")
expect(io.type(handle)):equals("file")
expect(io.type(io.stdin)):equals("file")
end)
it("returns nil on values", function()
expect(io.type(8)):equals(nil)
end)
it("returns nil on tables", function()
expect(io.type(setmetatable({}, {}))):equals(nil)
end)
end)
describe("io.lines", function()
it("validates arguments", function()
io.lines(nil)
expect.error(io.lines, ""):eq("/: No such file")
expect.error(io.lines, false):eq("bad argument #1 (expected string, got boolean)")
end)
it("closes the file", function()
setup()
local n = 0
local f = io.lines(file)
while f() do n = n + 1 end
expect(n):eq(6)
expect.error(f):eq("file is already closed")
expect.error(f):eq("file is already closed")
end)
it("can copy a file", function()
setup()
local n = 0
io.output(otherfile)
for l in io.lines(file) do
io.write(l, "\n")
n = n + 1
end
io.close()
expect(n):eq(6)
io.input(file)
local f = io.open(otherfile):lines()
local n = 0
for l in io.lines() do
expect(l):eq(f())
n = n + 1
end
expect(n):eq(6)
end)
it("does not close on a normal file handle", function()
setup()
local f = assert(io.open(file))
local n = 0
for _ in f:lines() do n = n + 1 end
expect(n):eq(6)
expect(tostring(f):sub(1, 5)):eq("file ")
assert(f:close())
expect(tostring(f)):eq("file (closed)")
expect(io.type(f)):eq("closed file")
end)
it("accepts multiple arguments", function()
write_file(file, "0123456789\n")
for a, b in io.lines(file, 1, 1) do
if a == "\n" then
expect(b):eq(nil)
else
expect(tonumber(a)):eq(tonumber(b) - 1)
end
end
for a, b, c in io.lines(file, 1, 2, "a") do
expect(a):eq("0")
expect(b):eq("12")
expect(c):eq("3456789\n")
end
for a, b, c in io.lines(file, "a", 0, 1) do
if a == "" then break end
expect(a):eq("0123456789\n")
expect(b):eq(nil)
expect(c):eq(nil)
end
write_file(file, "00\n10\n20\n30\n40\n")
for a, b in io.lines(file, "n", "n") do
if a == 40 then
expect(b):eq(nil)
else
expect(a):eq(b - 10)
end
end
end)
end)
describe("io.open", function()
it("validates arguments", function()
io.open("")
io.open("", "r")
expect.error(io.open, nil):eq("bad argument #1 (expected string, got nil)")
expect.error(io.open, "", false):eq("bad argument #2 (expected string, got boolean)")
end)
it("checks the mode", function()
io.open(file, "w"):close()
-- This really should be invalid mode, but I'll live.
expect.error(io.open, file, "rw"):str_match("Unsupported mode")
-- TODO: expect.error(io.open, file, "rb+"):str_match("Unsupported mode")
expect.error(io.open, file, "r+bk"):str_match("Unsupported mode")
expect.error(io.open, file, ""):str_match("Unsupported mode")
expect.error(io.open, file, "+"):str_match("Unsupported mode")
expect.error(io.open, file, "b"):str_match("Unsupported mode")
assert(io.open(file, "r+b")):close()
assert(io.open(file, "r+")):close()
assert(io.open(file, "rb")):close()
end)
it("returns an error message on non-existent files", function()
local a, b = io.open('xuxu_nao_existe')
expect(a):equals(nil)
expect(b):type("string")
end)
end)
describe("a readable handle", function()
it("cannot be written to", function()
write_file(file, "")
io.input(file)
expect { io.input():write("xuxu") }:same { nil, "file is not writable" }
io.input(io.stdin)
end)
it("supports various modes", function()
write_file(file, "alo\n " .. t .. " ;end of file\n")
io.input(file)
expect(io.read()):eq("alo")
expect(io.read(1)):eq(' ')
expect(io.read(#t)):eq(t)
expect(io.read(1)):eq(' ')
expect(io.read(0))
expect(io.read('*a')):eq(';end of file\n')
expect(io.read(0)):eq(nil)
expect(io.close(io.input())):eq(true)
fs.delete(file)
end)
it("support seeking", function()
setup()
io.input(file)
expect(io.read(0)):eq("") -- not eof
expect(io.read(5, '*l')):eq('"<22>lo"')
expect(io.read(0)):eq("")
expect(io.read()):eq("second line")
local x = io.input():seek()
expect(io.read()):eq("third line ")
assert(io.input():seek("set", x))
expect(io.read('*l')):eq("third line ")
expect(io.read(1)):eq("<EFBFBD>")
expect(io.read(#"fourth_line")):eq("fourth_line")
assert(io.input():seek("cur", -#"fourth_line"))
expect(io.read()):eq("fourth_line")
expect(io.read()):eq("") -- empty line
expect(io.read(8)):eq('\9\9 3450') -- FIXME: Not actually supported
expect(io.read(1)):eq('\n')
expect(io.read(0)):eq(nil) -- end of file
expect(io.read(1)):eq(nil) -- end of file
expect(({ io.read(1) })[2]):eq(nil)
expect(io.read()):eq(nil) -- end of file
expect(({ io.read() })[2]):eq(nil)
expect(io.read('*n')):eq(nil) -- end of file
expect(({ io.read('*n') })[2]):eq(nil)
expect(io.read('*a')):eq('') -- end of file (OK for `*a')
expect(io.read('*a')):eq('') -- end of file (OK for `*a')
io.close(io.input())
end)
it("supports the 'L' mode", function()
write_file(file, "\n\nline\nother")
io.input(file)
expect(io.read"L"):eq("\n")
expect(io.read"L"):eq("\n")
expect(io.read"L"):eq("line\n")
expect(io.read"L"):eq("other")
expect(io.read"L"):eq(nil)
io.input():close()
local f = assert(io.open(file))
local s = ""
for l in f:lines("L") do s = s .. l end
expect(s):eq("\n\nline\nother")
f:close()
io.input(file)
s = ""
for l in io.lines(nil, "L") do s = s .. l end
expect(s):eq("\n\nline\nother")
io.input():close()
s = ""
for l in io.lines(file, "L") do s = s .. l end
expect(s):eq("\n\nline\nother")
s = ""
for l in io.lines(file, "l") do s = s .. l end
expect(s):eq("lineother")
write_file(file, "a = 10 + 34\na = 2*a\na = -a\n")
local t = {}
load(io.lines(file, "L"), nil, nil, t)()
expect(t.a):eq(-((10 + 34) * 2))
end)
end)
describe("a writable handle", function()
it("supports seeking", function()
fs.delete(file)
io.output(file)
expect(io.output()):not_equals(io.stdout)
expect(io.output():seek()):equal(0)
assert(io.write("alo alo"))
expect(io.output():seek()):equal(#"alo alo")
expect(io.output():seek("cur", -3)):equal(#"alo alo" - 3)
assert(io.write("joao"))
expect(io.output():seek("end")):equal(#"alo joao")
expect(io.output():seek("set")):equal(0)
assert(io.write('"<22>lo"', "{a}\n", "second line\n", "third line \n"))
assert(io.write('<EFBFBD>fourth_line'))
io.output(io.stdout)
expect(io.output()):equals(io.stdout)
end)
it("supports appending", function()
io.output(file)
io.write("alo\n")
io.close()
expect.error(io.write)
local f = io.open(file, "a")
io.output(f)
assert(io.write(' ' .. t .. ' '))
assert(io.write(';', 'end of file\n'))
f:flush()
io.flush()
f:close()
expect(read_all(file)):eq("alo\n " .. t .. " ;end of file\n")
end)
end)
end)