mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-30 23:37:23 -04:00
CLOSES #1275, CLOSES #1295, CLOSES #1384, CLOSES #1628, CLOSES #1677, CLOSES #1682, CLOSES #1691, CLOSES #1813, CLOSES #1822, CLOSES #1861, CLOSES #1867, CLOSES #1868, CLOSES #1869, CLOSES #1870, CLOSES #1871, CLOSES #1872, CLOSES #1874, CLOSES #1876, CLOSES #1878, CLOSES #1880, CLOSES #1881, CLOSES #1882, CLOSES #1884, CLOSES #1885, CLOSES #1886, CLOSES #1887, CLOSES #1888, CLOSES #1889, CLOSES #1890, CLOSES #1891, CLOSES #1892, CLOSES #1893, CLOSES #1894, CLOSES #1895, CLOSES #1896, CLOSES #1899, CLOSES #1900, CLOSES #1901
CLOSES #1275, CLOSES #1295, CLOSES #1384, CLOSES #1628, CLOSES #1677, CLOSES #1682, CLOSES #1691, CLOSES #1813, CLOSES #1822, CLOSES #1861, CLOSES #1867, CLOSES #1868, CLOSES #1869, CLOSES #1870, CLOSES #1871, CLOSES #1872, CLOSES #1874, CLOSES #1876, CLOSES #1878, CLOSES #1880, CLOSES #1881, CLOSES #1882, CLOSES #1884, CLOSES #1885, CLOSES #1886, CLOSES #1887, CLOSES #1888, CLOSES #1889, CLOSES #1890, CLOSES #1891, CLOSES #1892, CLOSES #1893, CLOSES #1894, CLOSES #1895, CLOSES #1896, CLOSES #1899, CLOSES #1900, CLOSES #1901
This commit is contained in:
@@ -493,9 +493,49 @@ do
|
||||
}, {}, state)
|
||||
eng:unlink()
|
||||
pump(eng, 3)
|
||||
T.eq(eng.phase, "error", "a failed revocation is surfaced")
|
||||
T.eq(eng:linked(), true,
|
||||
"and the device stays linked rather than lying about it")
|
||||
T.eq(eng:linked(), false,
|
||||
"a server that refuses the revocation still unlinks this device")
|
||||
T.neq(eng.phase, "error", "so the player is not left stuck on a red status")
|
||||
end
|
||||
|
||||
do
|
||||
local state = linkedState()
|
||||
state.deviceId = "0a1b2c3d"
|
||||
local transport = {
|
||||
begin = function() return 1 end,
|
||||
poll = function()
|
||||
return { status = "error",
|
||||
err = "fetch failed for http://sync.test/sync/unlink: " ..
|
||||
"curl: (28) timed out" }
|
||||
end,
|
||||
release = function() end,
|
||||
}
|
||||
local eng = SyncEngine.new({
|
||||
baseUrl = "http://sync.test", transport = transport, state = state,
|
||||
saves = fakeSaves({}), persist = false,
|
||||
now = function() return 1700001000 end,
|
||||
})
|
||||
eng:unlink()
|
||||
pump(eng, 3)
|
||||
T.eq(eng:linked(), false,
|
||||
"an unreachable server does not trap the device as linked")
|
||||
T.eq(eng.status, "Not set up", "and the modal says the device is unlinked")
|
||||
end
|
||||
|
||||
do
|
||||
local state = linkedState()
|
||||
state.deviceId = "0a1b2c3d"
|
||||
local eng, transport = engine({
|
||||
["GET /sync/state"] = { code = 200, body = '{"saves":{}}' },
|
||||
["POST /sync/unlink"] = { code = 200, body = '{"ok":true,"devices":1}' },
|
||||
}, {}, state)
|
||||
eng.pending = { handle = 99 }
|
||||
T.eq(eng:busy(), true, "a request is in flight")
|
||||
eng:unlink()
|
||||
T.eq(transport.sent[1].url, "http://sync.test/sync/unlink",
|
||||
"unlink cancels it instead of refusing as busy")
|
||||
pump(eng, 3)
|
||||
T.eq(eng:linked(), false, "and the device is unlinked")
|
||||
end
|
||||
|
||||
do
|
||||
@@ -710,4 +750,102 @@ do
|
||||
"an apply that never asked imports nothing: silence is not consent")
|
||||
end
|
||||
|
||||
do
|
||||
T.eq(SyncEngine.unixSeconds(0), nil, "a zero stamp is no stamp")
|
||||
T.eq(SyncEngine.unixSeconds(-5), nil, "and neither is a negative one")
|
||||
T.eq(SyncEngine.unixSeconds(1700000000), 1700000000, "a real stamp survives")
|
||||
T.eq(SyncEngine.displayMeta({ savedAt = 0, sessionStart = 0 }).savedAt, nil,
|
||||
"the prompt is never handed a stamp it would date 1969")
|
||||
T.eq(SyncEngine.overlaps({ sessionStart = 0, savedAt = 0 },
|
||||
{ sessionStart = 0, savedAt = 0 }), false,
|
||||
"two server-zeroed windows do not overlap in 1970")
|
||||
T.eq(SyncEngine.samePlaytime({ playTime = 0 }, { playTime = 0 }), false,
|
||||
"a server-zeroed playtime is unknown, not zero minutes")
|
||||
end
|
||||
|
||||
do
|
||||
local SaveData = require("src.core.SaveData")
|
||||
local raw = "return { player = { name = 'GOLD' }, savedAt = 1700000500 }"
|
||||
local slots = { { id = "slot1", exists = true } }
|
||||
local realList, realRead, realDecode, realSummary, realOptions =
|
||||
SaveData.listSlots, SaveData.readSlotSource, SaveData.decode,
|
||||
SaveData.slotSummary, SaveData.loadOptions
|
||||
SaveData.listSlots = function(version)
|
||||
return version == "gold" and slots or {}
|
||||
end
|
||||
SaveData.readSlotSource = function() return raw end
|
||||
SaveData.decode = function() return { player = { name = "GOLD" },
|
||||
savedAt = 1700000500 } end
|
||||
SaveData.slotSummary = function()
|
||||
return "GOLD", { badges = 8, timeText = "3:46", dexCount = 9 }
|
||||
end
|
||||
SaveData.loadOptions = function()
|
||||
return { playthroughIds = { gold = { slot1 = "xyz" } } }
|
||||
end
|
||||
local list = SyncEngine.defaultSaves().list()
|
||||
SaveData.listSlots, SaveData.readSlotSource, SaveData.decode,
|
||||
SaveData.slotSummary, SaveData.loadOptions =
|
||||
realList, realRead, realDecode, realSummary, realOptions
|
||||
T.eq(#list, 1, "the Gold slot is listed")
|
||||
T.eq(list[1].meta.savedAt, 1700000500,
|
||||
"with the stamp gen2/Save.lua actually writes")
|
||||
end
|
||||
|
||||
do
|
||||
local state = linkedState()
|
||||
local entry = saveEntry("gold", "xyz", 1700000500, nil)
|
||||
entry.meta.summary = { name = "GOLD", badges = 8, timeText = "3:46",
|
||||
dexCount = 9 }
|
||||
local eng, transport = engine({
|
||||
["GET /sync/state"] = { code = 200,
|
||||
body = '{"saves":{"gold/xyz":{"rev":4,"meta":{"savedAt":0,' ..
|
||||
'"summary":{"name":"GOLD","badges":8,"timeText":"3:46",' ..
|
||||
'"dexCount":9}}}}}' },
|
||||
["PUT /sync/save"] = { code = 200, body = '{"ok":true,"rev":5}' },
|
||||
}, { entry }, state)
|
||||
|
||||
eng:syncNow()
|
||||
pump(eng)
|
||||
T.eq(#eng.conflicts, 0,
|
||||
"the same playthrough with an epoch-dated server row is not a fork")
|
||||
T.neq(eng.phase, "conflict", "so no duplicate-save prompt is raised")
|
||||
T.eq(SyncState.stamp(eng.state, "gold/xyz"), 1700000500,
|
||||
"and the upload leaves a stamp behind")
|
||||
local put
|
||||
for _, req in ipairs(transport.sent) do
|
||||
if req.method == "PUT" then put = req end
|
||||
end
|
||||
T.check(put ~= nil, "this device's copy is pushed instead")
|
||||
end
|
||||
|
||||
do
|
||||
local state = linkedState()
|
||||
SyncState.setRev(state, "gold/xyz", 4, 1700000500)
|
||||
local entry = saveEntry("gold", "xyz", 1700000500, nil)
|
||||
local eng, transport = engine({
|
||||
["GET /sync/state"] = { code = 200,
|
||||
body = '{"saves":{"gold/xyz":{"rev":4,"meta":{"savedAt":0}}}}' },
|
||||
}, { entry }, state)
|
||||
eng:syncNow()
|
||||
pump(eng)
|
||||
T.eq(#transport.sent, 1,
|
||||
"a Gold save at the rev it was uploaded at syncs no further")
|
||||
T.eq(eng.phase, "idle", "and the second boot is idle")
|
||||
end
|
||||
|
||||
do
|
||||
local state = linkedState()
|
||||
SyncState.setRev(state, "gold/xyz", 4, nil)
|
||||
local entry = saveEntry("gold", "xyz", nil, nil)
|
||||
local eng, transport = engine({
|
||||
["GET /sync/state"] = { code = 200,
|
||||
body = '{"saves":{"gold/xyz":{"rev":4,"meta":{"savedAt":0}}}}' },
|
||||
}, { entry }, state)
|
||||
eng:syncNow()
|
||||
pump(eng)
|
||||
T.eq(#transport.sent, 1,
|
||||
"an older Gold save with no stamp on either side is not dirty every boot")
|
||||
T.eq(eng.phase, "idle", "so the launcher settles")
|
||||
end
|
||||
|
||||
T.finish("sync_engine")
|
||||
|
||||
Reference in New Issue
Block a user