Files
gen1recomp/tests/gen2_save_convert_cli_test.lua
T
bryanthaboi ae6cac89e1 G2 support
2026-08-11 11:53:30 -04:00

103 lines
3.5 KiB
Lua

-- The standalone .sav converter refuses a Gen 2 save, ROM-free.
-- luajit tests/gen2_save_convert_cli_test.lua
-- Also dofile'd by tests/run_tests.lua.
--
-- src/save_convert/GenSave.lua models Gen 1 SRAM only, and SaveConvert answers
-- a plain refusal for a Gen 2 game rather than pushing a Gen 2 save table
-- through Gen 1 offsets. That refusal keys on the game the caller names, so
-- the CLI has to name one: tools/save_convert/convert.lua runs the real
-- binary here (a subprocess, not the library) because the hole this covers was
-- exactly the two call sites in it that passed no game at all.
package.path = "./?.lua;./?/init.lua;" .. package.path
local S = require("tests.harness").suite("gen2 save convert cli")
local check = S.check
local SaveSerializer = require("src.core.SaveSerializer")
local function run(cmd)
local pipe = io.popen(cmd .. " 2>&1")
if not pipe then return nil end
local out = pipe:read("*a")
pipe:close()
return out or ""
end
local probe = run("luajit -v")
if not probe or not probe:find("LuaJIT") then
check(true, "luajit not on PATH : SKIP")
S.finish()
return
end
local function tmp(name)
local dir = os.getenv("TMPDIR") or "/tmp/"
if dir:sub(-1) ~= "/" then dir = dir .. "/" end
return dir .. "gen2-cli-" .. name
end
local function write(path, text)
local f = assert(io.open(path, "w"))
f:write(text)
f:close()
end
local function exists(path)
local f = io.open(path, "rb")
if f then f:close() return true end
return false
end
-- A Gold slot as src/core/gen2/Save.lua writes it: `generation`/`version` at
-- the top level, and party rows carrying fields Gen 1 never had.
local goldPath = tmp("gold.lua")
local outPath = tmp("gold.sav")
os.remove(outPath)
write(goldPath, SaveSerializer.encode({
format = 7, generation = 2, version = "gold",
player = { name = "GOLD", money = 3000 },
party = { { species = "TOTODILE", level = 5, happiness = 70, pokerus = 0,
dvs = { atk = 15, def = 15, spd = 15, spc = 15 } } },
}))
local out = run(("luajit tools/save_convert/convert.lua export %q %q")
:format(goldPath, outPath))
check(out:find("Gen 2 cart save", 1, true) ~= nil,
"exporting a Gold save.lua is refused by name: " .. (out:gsub("%s+$", "")))
check(not exists(outPath),
"and no 32768-byte file that looks like a Red battery is written")
-- The same gate on the way in, when the caller names the game.
local savPath = tmp("in.sav")
local outPath2 = tmp("in.lua")
os.remove(outPath2)
write(savPath, string.rep("\0", 32768))
out = run(("luajit tools/save_convert/convert.lua import %q %q gold")
:format(savPath, outPath2))
check(out:find("Gen 2 cart save", 1, true) ~= nil,
"importing for a Gen 2 game is refused too")
check(not exists(outPath2), "and writes nothing")
-- Gen 1 keeps working: a Red-shaped save is never caught by the Gen 2 gate.
-- (Whether the export then succeeds depends on data/generated/ being built,
-- which this suite deliberately does not require.)
local redPath = tmp("red.lua")
local outPath3 = tmp("red.sav")
os.remove(outPath3)
write(redPath, SaveSerializer.encode({
meta = { format = "gen1_import", version = "red" },
player = { name = "RED", money = 3000 },
party = {},
}))
out = run(("luajit tools/save_convert/convert.lua export %q %q")
:format(redPath, outPath3))
check(not out:find("Gen 2 cart save", 1, true),
"a Gen 1 save is not refused: " .. (out:gsub("%s+$", "")))
for _, path in ipairs({ goldPath, outPath, savPath, outPath2, redPath,
outPath3 }) do
os.remove(path)
end
S.finish()