Files
gen1recomp/tests/engine/sync_state_test.lua
T
2026-08-19 05:57:44 -04:00

121 lines
4.3 KiB
Lua

package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
love = love or require("tests.love_stub")
local SaveData = require("src.core.SaveData")
local SyncState = require("src.sync.SyncState")
local realFS = love.filesystem
local function memfs(files)
return {
files = files,
write = function(path, content) files[path] = content return true end,
read = function(path) return files[path] end,
remove = function(path) files[path] = nil return true end,
getInfo = function(path)
if files[path] then return { type = "file" } end
return nil
end,
}
end
local function fresh()
local files = {}
love.filesystem = memfs(files)
SaveData.resetSlotState()
return files
end
do
local opts = SaveData.defaultOptions()
T.check(type(opts.saveSync) == "table", "defaultOptions carries saveSync")
T.eq(opts.saveSync.enabled, false, "sync is off until the player sets it up")
T.check(type(opts.saveSync.revs) == "table", "and starts with no synced revs")
T.eq(opts.saveSync.account, nil, "and no account")
local state = SyncState.defaults()
T.eq(SyncState.linked(state), false, "a default state is not linked")
T.eq(state.lastSyncAt, 0, "and has never synced")
end
do
local dirty = SyncState.sanitize({
enabled = "yes",
account = "aa11bb22cc33dd44",
deviceToken = "tok",
deviceLabel = "",
lastSyncAt = 0 / 0,
code1 = "12345678",
code2 = "87654321",
revs = { ["red/aaa"] = 4, [7] = 9, ["red/bad"] = "no" },
stamps = { ["red/aaa"] = 1700 },
pendingConflicts = { { key = "red/aaa", version = "red", overlap = true },
{ nope = true } },
})
T.eq(dirty.enabled, false, "a non-boolean enabled reads as off")
T.eq(dirty.account, "aa11bb22cc33dd44", "the account id survives")
T.eq(dirty.deviceLabel, nil, "an empty device label is dropped")
T.eq(dirty.lastSyncAt, 0, "a NaN lastSyncAt is refused")
T.eq(dirty.code1, nil, "the first account code is never kept")
T.eq(dirty.code2, nil, "nor the second")
T.eq(dirty.revs["red/aaa"], 4, "numeric revs survive")
T.eq(dirty.revs["red/bad"], nil, "a non-numeric rev is dropped")
T.eq(dirty.revs[7], nil, "a non-string rev key is dropped")
T.eq(dirty.stamps["red/aaa"], 1700, "the savedAt stamp survives")
T.eq(#dirty.pendingConflicts, 1, "only well-formed conflicts are kept")
T.eq(dirty.pendingConflicts[1].overlap, true, "with their overlap flag")
end
do
local files = fresh()
local state = SyncState.load()
T.eq(SyncState.linked(state), false, "a first boot has no linked account")
state.account = "aa11bb22cc33dd44"
state.deviceToken = "feedface"
state.deviceId = "0a1b2c3d"
state.deviceLabel = "laptop"
state.enabled = true
state.code1 = "12345678"
SyncState.setRev(state, SyncState.key("red", "abc"), 3, 1700000000)
SyncState.save(state)
T.check(files["options.lua"] ~= nil, "the state lands in options.lua")
T.eq(files["options.lua"]:find("12345678", 1, true), nil,
"the account codes are never written to disk")
local back = SyncState.load()
T.eq(SyncState.linked(back), true, "the linked account survives a reload")
T.eq(back.deviceLabel, "laptop", "and the device label")
T.eq(back.deviceId, "0a1b2c3d",
"and the device id the server revokes tokens by")
T.eq(SyncState.rev(back, "red/abc"), 3, "and the last synced rev")
T.eq(SyncState.stamp(back, "red/abc"), 1700000000, "and the savedAt stamp")
T.eq(back.code1, nil, "the code is gone from the reloaded state")
local opts = SaveData.loadOptions()
T.eq(opts.textSpeed, 3, "writing sync state leaves other options alone")
SyncState.forget(back, "red/abc")
T.eq(SyncState.rev(back, "red/abc"), nil, "forget drops the rev")
T.eq(SyncState.stamp(back, "red/abc"), nil, "and the stamp")
SyncState.clear()
T.eq(SyncState.linked(SyncState.load()), false, "clear unlinks the device")
end
do
T.eq(SyncState.key("red", "abc"), "red/abc", "keys join version and id")
T.eq(SyncState.key("red", ""), nil, "an empty playthrough id has no key")
T.eq(SyncState.key(nil, "abc"), nil, "and neither does a missing version")
local version, id = SyncState.splitKey("gold/deadbeef")
T.eq(version, "gold", "splitKey reads the version back")
T.eq(id, "deadbeef", "and the playthrough id")
end
love.filesystem = realFS
T.finish("sync_state")