-- Lua's io library against a file that exists only inside a .game. Singe hands those out as its -- own file object, which reads the database row where it lies rather than unpacking it to a copy, -- so everything below has to behave exactly as it would on a loose file. -- -- It has to be run packed, with no loose copy beside the container -- a loose file shadows the -- packed one and the whole test then proves nothing -- so from a directory holding this folder: -- -- Singe -P packedIo packedIo.game -- rm -rf packedIo -- Singe -w -C 720x480 packedIo.game -- -- It prints one line: IOTEST pass=N fail=0. Every failure prints what it wanted first. dofile("Singe/Framework.singe") local pass = 0 local fail = 0 local function check(what, got, want) if got == want then pass = pass + 1 else fail = fail + 1 debugPrint(string.format("FAIL %s: got %s, wanted %s", what, tostring(got), tostring(want))) end end -- Reading, seeking, and what each format answers at the end of the file. local f = io.open("packedIo/lines.txt", "rb") check("io.type", io.type(f), "file") check("read a", f:read("a"), "alpha\nbeta\ngamma\n") check("read a at end", f:read("a"), "") check("seek set", f:seek("set", 0), 0) check("read l", f:read("l"), "alpha") check("read L", f:read("L"), "beta\n") check("read 3", f:read(3), "gam") check("read l rest", f:read("l"), "ma") check("read l at end", f:read("l"), nil) check("seek end", f:seek("end", 0), 17) check("seek cur back", f:seek("cur", -6), 11) check("read after seek", f:read("l"), "gamma") f:close() check("io.type closed", io.type(f), "closed file") -- Iterating, both ways round. io.lines closes at the end; f:lines leaves the file alone. local seen = {} for line in io.lines("packedIo/lines.txt") do seen[#seen + 1] = line end check("io.lines count", #seen, 3) check("io.lines last", seen[3], "gamma") local g = io.open("packedIo/lines.txt") local count = 0 for _ in g:lines("L") do count = count + 1 end check("f:lines count", count, 3) check("f:lines leaves it open", io.type(g), "file") g:close() -- Numbers, and the default input. local n = io.open("packedIo/numbers.txt") check("read n", n:read("n"), 12) check("read n again", n:read("n"), 34.5) check("read n hex", n:read("n"), 16) n:close() io.input("packedIo/numbers.txt") check("io.read after io.input", io.read("l"), "12 34.5 0x10") check("io.input() answers", io.type(io.input()), "file") io.close() -- A last line with no ending on it. local t = io.open("packedIo/tail.txt") check("read l unterminated", t:read("l"), "no newline at the end") check("read l past it", t:read("l"), nil) t:close() -- A packed asset is read only, and a name that is not there answers the way Lua does. local w = io.open("packedIo/lines.txt") check("write refused", pcall(function() w:write("x") end), false) w:close() local missing, message = io.open("packedIo/nothere.txt") check("missing is nil", missing, nil) check("missing has a message", type(message), "string") -- And a real file in the data directory still behaves as it always did. local loose = io.open(singeGetDataPath() .. "loose.txt", "w") loose:write("written\n") loose:close() local back = io.open(singeGetDataPath() .. "loose.txt") check("loose round trip", back:read("l"), "written") check("loose is a file", io.type(back), "file") back:close() debugPrint(string.format("IOTEST pass=%d fail=%d", pass, fail)) singeQuit() function onOverlayUpdate() return OVERLAY_NOT_UPDATED end