Files
gen1recomp/tests/engine/save_editor_options_2388.lua
2026-09-25 07:25:23 -04:00

122 lines
5.1 KiB
Lua

package.path = package.path .. ";./?.lua;./?/init.lua;./tools/save-editor/?.lua"
.. ";./tools/save-editor/panels/?.lua"
love = require("tests.love_stub")
local passed, failed = 0, 0
local function check(cond, msg)
if cond then
passed = passed + 1
else
failed = failed + 1
print("FAIL: " .. msg)
end
end
local function eq(a, b, msg)
check(a == b, msg .. string.format(" (got %s, want %s)", tostring(a), tostring(b)))
end
local SaveData = require("src.core.SaveData")
local SaveSerializer = require("src.core.SaveSerializer")
local SessionLifecycle = require("src.core.SessionLifecycle")
local FsIo = require("tests.fs_io")
local Ops = require("Ops")
local App = require("App")
local fs = love.filesystem
local ffi = require("ffi")
local setVar
if ffi.os == "Windows" then
ffi.cdef([[ int _putenv(const char *envstring); ]])
setVar = function(name, value) ffi.C._putenv(name .. "=" .. value) end
else
ffi.cdef([[
int setenv(const char *name, const char *value, int overwrite);
int unsetenv(const char *name);
]])
setVar = function(name, value)
if value == "" then ffi.C.unsetenv(name) else ffi.C.setenv(name, value, 1) end
end
end
local originalDataDir = os.getenv("POKEPORT_DATA_DIR")
setVar("POKEPORT_DATA_DIR", "tests/fixture_data")
do
local opts = SaveData.loadOptions()
opts.battleLayout, opts.battleFit, opts.battleHud, opts.battleBg = "wide", "fixed", "extended", "world"
opts.colors, opts.tilt = "og", 2
SaveData.saveOptions(opts)
local slotId = SaveData.createSlot("red")
check(slotId ~= nil, "a red slot is created")
SaveData.setActiveSlot("red", slotId)
local before = fs.read("options.lua")
check(type(before) == "string" and before:find("wide", 1, true) ~= nil, "options.lua holds WIDE before the edit")
local save = SaveData.newGame()
save.player.name = "ASH"
save.options = { battleLayout = "og", battleBg = "white", colors = "gbc", tilt = 0, videoMode = "windowed" }
check(SaveData.writeSlot("red", slotId, save) == true, "writeSlot writes the slot")
eq(save.options.battleLayout, "og", "writeSlot leaves the caller's table alone")
local slotBody = SaveData.readSlotSource("red", slotId)
check(slotBody ~= nil, "the slot reads back")
local slotTable = slotBody and SaveSerializer.decode(slotBody)
check(slotTable ~= nil and slotTable.options == nil, "writeSlot strips options from a gen1 slot")
eq(fs.read("options.lua"), before, "writeSlot does not touch options.lua")
local tmpBase = os.tmpname()
local tmpPath = tmpBase .. "-options-2388.lua"
local f = io.open(tmpPath, "wb")
f:write(slotBody)
f:close()
App.load(tmpPath, { version = "red", slotId = slotId, embedded = true, onClose = function() end })
local s = App.getState()
check(s ~= nil and s.loadError == false, "the editor opens the slot")
Ops.addMoney(s, 10)
s.save.pokedex = s.save.pokedex or {}
s.save.pokedex.owned = s.save.pokedex.owned or {}
s.save.pokedex.owned.PIKACHU = true
s.dirty = true
App.save()
eq(fs.read("options.lua"), before, "App.save leaves options.lua byte-identical")
pcall(SessionLifecycle.endEditorSession, { version = "red", app = App })
eq(fs.read("options.lua"), before, "closing the editor leaves options.lua byte-identical")
local rf = io.open(tmpPath, "rb")
local edited = rf and rf:read("*a") or ""
if rf then rf:close() end
local editedTable = SaveSerializer.decode(edited)
check(editedTable ~= nil, "the edited slot decodes")
check(editedTable and editedTable.options == nil, "the edited slot has no options key")
check(editedTable and editedTable.pokedex and editedTable.pokedex.owned
and editedTable.pokedex.owned.PIKACHU == true, "the dex edit landed")
check(SaveData.writeSlot("red", slotId, editedTable) == true, "the edited slot writes back")
local loaded = SaveData.load("red")
check(loaded ~= nil, "the edited slot loads")
eq(loaded and loaded.options and loaded.options.battleLayout, "wide", "battle layout stays WIDE after an edit")
eq(loaded and loaded.options and loaded.options.battleBg, "world", "battle bg stays WORLD after an edit")
eq(loaded and loaded.options and loaded.options.battleHud, "extended", "battle hud stays EXTENDED after an edit")
eq(loaded and loaded.options and loaded.options.colors, "og", "colors stay OG after an edit")
eq(fs.read("options.lua") and SaveSerializer.decode(fs.read("options.lua")).battleLayout, "wide",
"options.lua still says WIDE after the load")
os.remove(tmpPath)
os.remove(tmpBase)
for _, bak in ipairs(FsIo.globPrefix(tmpPath .. ".bak-")) do os.remove(bak) end
end
do
local slotId = SaveData.createSlot("firered")
if slotId then
local save = { engine = "game3", version = "firered", name = "RED", options = { textSpeed = 1, frameType = 3 } }
check(SaveData.writeSlot("firered", slotId, save) == true, "writeSlot writes a firered slot")
local back = SaveSerializer.decode(SaveData.readSlotSource("firered", slotId) or "")
eq(back and back.options and back.options.frameType, 3, "a gen3 slot keeps its in-save options block")
end
end
setVar("POKEPORT_DATA_DIR", originalDataDir or "")
print(string.format("save editor options 2388: %d passed, %d failed", passed, failed))
if failed > 0 then os.exit(1) end