mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
225 lines
8.5 KiB
Lua
225 lines
8.5 KiB
Lua
#!/usr/bin/env luajit
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
require("tests.fixture_data.game3_items").install()
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local function eq(a, b, msg)
|
|
check(a == b, string.format("%s (%s == %s)", msg, tostring(a), tostring(b)))
|
|
end
|
|
|
|
local okR, Relay = pcall(require, "tests.support.fake_relay")
|
|
if not okR then
|
|
print("[skip] tests/support/fake_relay.lua is not in this tree: " .. tostring(Relay))
|
|
os.exit(0)
|
|
end
|
|
|
|
local function newClientModule()
|
|
package.loaded["src.online.Client"] = nil
|
|
local Client = require("src.online.Client")
|
|
Client.reset()
|
|
return Client
|
|
end
|
|
|
|
local PROFILE = {
|
|
engine = 3, version = "firered", engineVersion = "0.0.0-dev", apiVersion = "2",
|
|
fingerprint = "g3fingerprint", rulesetId = "g3_link", kind = "vanilla", rule = {},
|
|
}
|
|
|
|
local relay = Relay.new()
|
|
local seatA = relay:seat("a0000001", "RED")
|
|
local seatB = relay:seat("b0000002", "BLUE")
|
|
|
|
local ClientB = newClientModule()
|
|
ClientB.configure({ relayAddress = "fake:1", connect = function() return seatB.transport end })
|
|
local ClientA = newClientModule()
|
|
ClientA.configure({ relayAddress = "fake:1", connect = function() return seatA.transport end })
|
|
|
|
local function step(n)
|
|
for _ = 1, n or 3 do
|
|
relay:pump()
|
|
ClientA.update(0)
|
|
ClientB.update(0)
|
|
end
|
|
end
|
|
|
|
ClientA.connect({ name = "RED", profiles = { PROFILE } })
|
|
ClientB.connect({ name = "BLUE", profiles = { PROFILE } })
|
|
step()
|
|
eq(ClientA.state(), "online", "A is online on the fake relay")
|
|
eq(ClientB.state(), "online", "B is online on the fake relay")
|
|
|
|
local session = { name = "RED", trainerId = 0x1234, gender = 0, party = {} }
|
|
package.loaded["src.core.game3.runtime"] = {
|
|
getSession = function() return session end,
|
|
isActive = function() return true end,
|
|
}
|
|
local RelayTransport = require("src.core.game3.link.relay_transport")
|
|
local Game3Link = require("src.link.Game3Link")
|
|
local game = { data = {}, save = { player = { name = "RED" }, options = {} } }
|
|
|
|
print("[test] 1. two AUTO queues pair into a relay room born battling")
|
|
ClientA.queueDirect({ activity = "trade", ruleset = "g3_link", auto = true, profile = PROFILE,
|
|
avatar = { name = "RED", trainerId = 1, gender = 0, version = "firered" }, preview = { 1 } })
|
|
step()
|
|
ClientB.queueDirect({ activity = "trade", ruleset = "g3_link", auto = true, profile = PROFILE,
|
|
avatar = { name = "BLUE", trainerId = 2, gender = 0, version = "leafgreen" }, preview = { 4 } })
|
|
step()
|
|
local roomA = ClientA.room()
|
|
check(roomA ~= nil, "A has a room")
|
|
eq(roomA and roomA.stage, "battling", "born battling")
|
|
check(roomA and roomA.match ~= nil, "with a match token")
|
|
eq(ClientA.seat(), 0, "A queued first: seat 0")
|
|
eq(ClientB.seat(), 1, "B: seat 1")
|
|
|
|
print("[test] 2. Game3Link handshakes over the real Client room sessions")
|
|
local tA = RelayTransport.new(ClientA.roomSession(), { client = ClientA })
|
|
local tB = RelayTransport.new(ClientB.roomSession(), { client = ClientB })
|
|
eq(tA:seat(), 0, "transport A is seat 0")
|
|
eq(tB:seat(), 1, "transport B is seat 1")
|
|
eq(tA:seed(), roomA.seed, "the relay seed")
|
|
local lA = Game3Link.attach(tA, { game = game })
|
|
local lB = Game3Link.attach(tB, { game = game, hello = Game3Link.hello(game,
|
|
Game3Link.LINKTYPE.TRADE, { name = "BLUE", trainerId = 2, gender = 0 }) })
|
|
for _ = 1, 4 do
|
|
step(1)
|
|
lA:update(0)
|
|
lB:update(0)
|
|
end
|
|
check(lA:isReady(), "A reached ready")
|
|
check(lB:isReady(), "B reached ready")
|
|
eq(lA:peerName(), "BLUE", "A names BLUE")
|
|
eq(lB:peerName(), "RED", "B names RED")
|
|
eq(lA.peerHellos[1] and lA.peerHellos[1].seat, 1, "the hello arrived tagged with seat 1")
|
|
|
|
print("[test] 3. messages cross the relay seat-tagged, the relay barrier commits")
|
|
lA:send({ type = "game3_trade_cmd", cmd = 0xAABB, cursor = 2 })
|
|
step(1)
|
|
lB:update(0)
|
|
local cmd = lB:take("game3_trade_cmd")
|
|
eq(cmd and cmd.cursor, 2, "B received the trade command")
|
|
eq(cmd and cmd.seat, 0, "from seat 0")
|
|
lA:send({ type = "game3_trade_confirm", digest = "0123456789abcdef" })
|
|
lB:send({ type = "game3_trade_confirm", digest = "0123456789abcdef" })
|
|
step(2)
|
|
lA:update(0)
|
|
local commit = lA:take("trade_commit")
|
|
check(commit ~= nil, "A receives the relay's trade_commit")
|
|
eq(commit and commit.seat, -1, "relay-authored")
|
|
|
|
print("[test] 4. closing the link keeps the room; leaving it drops the peer's link")
|
|
lA:close("done")
|
|
step(1)
|
|
check(ClientA.room() ~= nil, "A's link closed but A is still seated")
|
|
lA:leave()
|
|
step(2)
|
|
eq(ClientA.room(), nil, "A left the room")
|
|
lB:update(0)
|
|
lB:update(0)
|
|
check(not lB:isOpen(), "B's link closed")
|
|
check(lB.reason == "peer_left" or lB.reason == "peer_dropped", "because the peer left")
|
|
|
|
print("[test] 5. an invite from the launcher lands in the Union Room")
|
|
local store = { flags = {}, vars = {} }
|
|
session.store = store
|
|
session.map = "FR_UNION_ROOM"
|
|
local ctx = { specialVars = {}, stringVars = {} }
|
|
package.loaded["src.core.game3.runtime"]._game = { data = { maps = {} }, session = session,
|
|
input = { wasPressed = function() return false end }, save = game.save }
|
|
local romBundleEarly = require("tests.game3_cache").bundle()
|
|
package.loaded["src.core.game3.scripting.space"] = {
|
|
store = store, mapId = "FR_UNION_ROOM", vm = { ctx = ctx, adapters = { log = function() end } },
|
|
ensureBundle = function() return romBundleEarly end,
|
|
}
|
|
require("src.core.game3.link.union_room")._avatars = require("tests.g3link_fake_relay").avatars()
|
|
package.loaded["src.core.game3.objects"] = {
|
|
addObject = function() return true end, removeObject = function() return true end,
|
|
refreshGraphics = function() return 0 end,
|
|
}
|
|
package.loaded["src.core.game3.player"] = { cellX = 7, cellY = 11, facing = "down" }
|
|
package.loaded["src.online.ArenaData"] = {
|
|
liveProfile3 = function(_, rulesetId)
|
|
local p = {}
|
|
for k, v in pairs(PROFILE) do p[k] = v end
|
|
p.rulesetId = rulesetId
|
|
return p
|
|
end,
|
|
}
|
|
package.loaded["src.online.Client"] = ClientA
|
|
local romBundle = require("tests.game3_cache").bundle()
|
|
if not romBundle then
|
|
package.loaded["src.core.game3.rom_text"] = {
|
|
plain = function(key) return key end, box = function(key) return key end,
|
|
ascii = function(key) return key end, has = function() return true end,
|
|
ir = function(key) return { { t = "text", s = key } } end,
|
|
key = function(n, i, j) return j and (n .. "[" .. i .. "][" .. j .. "]") or (n .. "[" .. i .. "]") end,
|
|
at = function(n, i, j) return j and (n .. "[" .. i .. "][" .. j .. "]") or (n .. "[" .. i .. "]") end,
|
|
count = function() return 0 end, list = function() return {} end,
|
|
lazy = function(map) return setmetatable({}, { __index = function(_, k) return map[k] end }) end,
|
|
}
|
|
end
|
|
local Link = require("src.core.game3.link")
|
|
local Union = require("src.core.game3.link.union_room")
|
|
check(Link.adapterConnected(), "A's adapter reads connected")
|
|
Union.run(ctx)
|
|
eq(Union.relay, true, "the Union Room runs over the relay")
|
|
step()
|
|
check(ClientA.plaza() ~= nil, "A is in the union plaza")
|
|
seatB.presence.where = "launcher"
|
|
ClientB.invite("a0000001", "chat", {}, PROFILE)
|
|
step()
|
|
Union.update(1 / 60)
|
|
Union.pollIncoming()
|
|
eq(Union.state, "player_contacted_you", "B's invite reaches the Union Room")
|
|
eq(Union._requestName, "BLUE", "from BLUE")
|
|
Union.answerRequest(true)
|
|
step()
|
|
for _ = 1, 3 do
|
|
Link.update(1 / 60)
|
|
step(1)
|
|
end
|
|
eq(Union.state, "in_activity", "the chat began over the relay")
|
|
eq(Link.link, nil, "the chat talks to the room session, no Game3Link handshake")
|
|
eq(ClientA.seat(), 1, "the invited player sits in seat 1")
|
|
local Chat = require("src.core.game3.link.chat")
|
|
check(Chat.isActive(), "chat is live")
|
|
local rsB = ClientB.roomSession()
|
|
step(1)
|
|
local join = rsB:take("game3_union_hello")
|
|
eq(join and join.name, "RED", "A announced itself to the chat")
|
|
rsB:send({ type = "game3_union_hello", name = "BLUE", gender = 0, trainerId = 2, activity = 0x45 })
|
|
rsB:send({ type = "game3_chat_line", name = "BLUE", text = "HI RED" })
|
|
step(2)
|
|
Link.update(1 / 60)
|
|
eq(#Chat.lines, 2, "BLUE joined and spoke")
|
|
check(Chat.lines[2] and Chat.lines[2].text:find("HI RED", 1, true) ~= nil, "BLUE's line is in the log")
|
|
eq(Chat.lines[2] and Chat.lines[2].seat, 0, "in BLUE's seat colour")
|
|
Chat.stop("left")
|
|
for _ = 1, 3 do
|
|
Link.update(1 / 60)
|
|
step(1)
|
|
end
|
|
eq(Union.state, "main", "back in the Union Room")
|
|
eq(ClientA.room(), nil, "the private room was left")
|
|
local bye = rsB:take("game3_chat_bye")
|
|
check(bye ~= nil, "BLUE saw A leave the chat")
|
|
Union.stop("test")
|
|
step()
|
|
eq(ClientA.plaza(), nil, "leaving the Union Room leaves the plaza")
|
|
|
|
Link.reset()
|
|
if failed == 0 then
|
|
print("[pass] link over the Client")
|
|
os.exit(0)
|
|
end
|
|
print("[fail] link over the Client: " .. failed)
|
|
os.exit(1)
|