mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 05:32:07 -04:00
598 lines
25 KiB
Lua
598 lines
25 KiB
Lua
#!/usr/bin/env luajit
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
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
|
|
|
|
love = love or require("tests.love_stub")
|
|
|
|
local romBundle = require("tests.game3_cache").bundle()
|
|
if not romBundle then
|
|
local LIST_ROWS = { sListMenuItems_CardsOrNews = 3, sListMenuItems_ReceiveSendToss = 4, sListMenuItems_ReceiveToss = 3,
|
|
sListMenuItems_WirelessOrFriend = 3 }
|
|
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(n) return LIST_ROWS[n] or 0 end,
|
|
list = function(n)
|
|
local out = {}
|
|
for i = 0, (LIST_ROWS[n] or 0) - 1 do out[i + 1] = n .. "[" .. i .. "]" end
|
|
return out
|
|
end,
|
|
lazy = function(map) return setmetatable({}, { __index = function(_, k) return map[k] end }) end,
|
|
}
|
|
end
|
|
local function teq(a, b, msg)
|
|
if romBundle then eq(a, b, msg) else print("[skip] ROM text: " .. msg) end
|
|
end
|
|
local function tcheck(cond, msg)
|
|
if romBundle then check(cond, msg) else print("[skip] ROM text: " .. msg) end
|
|
end
|
|
|
|
local ListStub = {}
|
|
ListStub.__index = ListStub
|
|
ListStub.COLOR_WHITE = { fg = "ur_white" }
|
|
function ListStub.new(opts)
|
|
local lm = setmetatable({ opts = opts, items = opts.items, cursor = 1, draws = 0 }, ListStub)
|
|
ListStub.last = lm
|
|
return lm
|
|
end
|
|
function ListStub:handleInput(input)
|
|
if input:wasPressed("down") and self.cursor < #self.items then
|
|
self.cursor = self.cursor + 1
|
|
return "move"
|
|
elseif input:wasPressed("up") and self.cursor > 1 then
|
|
self.cursor = self.cursor - 1
|
|
return "move"
|
|
elseif input:wasPressed("a") then
|
|
return "select"
|
|
elseif input:wasPressed("b") then
|
|
return "cancel"
|
|
end
|
|
return nil
|
|
end
|
|
function ListStub:selected() return self.items[self.cursor], self.cursor end
|
|
function ListStub:update() end
|
|
function ListStub:draw() self.draws = self.draws + 1 end
|
|
package.loaded["src.ui.game3.list_menu"] = ListStub
|
|
|
|
local fanfares = {}
|
|
package.loaded["src.core.game3.audio"] = setmetatable({
|
|
playFanfare = function(id) fanfares[#fanfares + 1] = id return true end,
|
|
isFanfareFinished = function() return true end,
|
|
}, { __index = function() return function() end end })
|
|
|
|
local Boot = require("src.ui.game3.boot")
|
|
local Ui = require("src.ui.game3.mystery_gift")
|
|
local MysteryGift = require("src.core.game3.mystery_gift")
|
|
local WirelessIcon = require("src.ui.game3.wireless_icon")
|
|
|
|
local FLAG_SYS_MYSTERY_GIFT_ENABLED = 0x839
|
|
|
|
local FIXTURE_PUB = "58c5b57e548789c3d231a9537f172bcf515a39b053f58a90c7b0096967a746ba"
|
|
local FIXTURE_BODY = [==[{"v":1,"payload":"{\"cards\":[{\"bgType\":2,\"bodyText\":[\"Thank you for using the MYSTERY\",\"GIFT System.\",\"There is a ticket here for you.\",\"It is for use at VERMILION CITY port.\"],\"flagId\":1001,\"footerLine1Text\":\"Speak to the deliveryman\",\"footerLine2Text\":\"at a POKéMON CENTER.\",\"gift\":{\"haveFlags\":[680,754,755],\"item\":370,\"kind\":\"item\",\"quantity\":1,\"setFlags\":[2122,680]},\"iconSpecies\":0,\"idNumber\":1,\"key\":\"mystic_ticket\",\"maxStamps\":0,\"sendType\":0,\"subtitleText\":\"MYSTERY GIFT\",\"titleText\":\"MYSTIC TICKET\",\"type\":0},{\"bgType\":7,\"bodyText\":[\"A mythical POKéMON has been\",\"sent to you from the\",\"POKéMON CENTER.\",\"Please take good care of it.\"],\"flagId\":1007,\"footerLine1Text\":\"Speak to the deliveryman\",\"footerLine2Text\":\"at a POKéMON CENTER.\",\"gift\":{\"kind\":\"mon\",\"level\":10,\"moves\":{\"1\":1},\"otId\":20078,\"otName\":\"AURA\",\"species\":151},\"iconSpecies\":151,\"idNumber\":7,\"key\":\"mew\",\"maxStamps\":0,\"sendType\":0,\"subtitleText\":\"MYSTERY GIFT\",\"titleText\":\"MEW\",\"type\":0},{\"bgType\":4,\"bodyText\":[\"Thank you for using the STAMP CARD\",\"System.\",\"Trade with other TRAINERS to fill\",\"your STAMP CARD.\"],\"flagId\":1004,\"footerLine1Text\":\"Speak to the deliveryman\",\"footerLine2Text\":\"at a POKéMON CENTER.\",\"gift\":{\"kind\":\"none\"},\"iconSpecies\":0,\"idNumber\":4,\"key\":\"stamp_card\",\"maxStamps\":7,\"sendType\":1,\"subtitleText\":\"MYSTERY GIFT\",\"titleText\":\"STAMP CARD\",\"type\":1}],\"issued\":0,\"news\":[{\"bgType\":1,\"bodyText\":[\"Welcome to the POKéMON\",\"WIRELESS CLUB news.\",\"Look for new WONDER CARDS.\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"],\"id\":1,\"key\":\"launch_news\",\"sendType\":0,\"titleText\":\"WONDER NEWS\"}],\"v\":1}","sig":"44aa8146ee6d745efe81afc3427aaf84d07b4c64bacb6922c8d9ff27fa779e3d628c55cd623ab49c9afc2fc84f02be8942350cae4ae08c1e4e01955a671d7009","key":"58c5b57e548789c3d231a9537f172bcf515a39b053f58a90c7b0096967a746ba"}]==]
|
|
|
|
local function transport(reply)
|
|
local t = { calls = 0 }
|
|
function t:begin() self.calls = self.calls + 1 return self.calls end
|
|
function t:poll()
|
|
if type(reply) == "function" then return reply() end
|
|
return reply
|
|
end
|
|
function t:release() end
|
|
function t:cancel() self.canceled = true end
|
|
return t
|
|
end
|
|
|
|
local function okFeed()
|
|
return transport({ status = "ok", code = 200, body = FIXTURE_BODY })
|
|
end
|
|
|
|
MysteryGift.GIFT_PUBKEY = FIXTURE_PUB
|
|
|
|
local function driver(st)
|
|
local keys = {}
|
|
local function pressed(k) return keys[k] == true end
|
|
local d = {}
|
|
function d.step(k)
|
|
keys = {}
|
|
if k then keys[k] = true end
|
|
Ui.update(st, pressed, 1 / 60)
|
|
end
|
|
function d.waitFor(pred, key, limit)
|
|
for _ = 1, limit or 2000 do
|
|
if pred() then return true end
|
|
if st.msg and st.msg.revealed >= st.msg.total and not st.msg.auto and not st.msg.hold then
|
|
d.step(key or "a")
|
|
else
|
|
d.step(nil)
|
|
end
|
|
end
|
|
return pred()
|
|
end
|
|
function d.finishMessage()
|
|
for _ = 1, 2000 do
|
|
if not st.msg then return end
|
|
if st.msg.revealed >= st.msg.total and not st.msg.auto and not st.msg.hold then
|
|
d.step("a")
|
|
return
|
|
end
|
|
d.step(nil)
|
|
end
|
|
end
|
|
return d
|
|
end
|
|
|
|
local function giftSession(save)
|
|
local sess = MysteryGift.sessionFromSave(save)
|
|
MysteryGift.enable(sess)
|
|
return sess
|
|
end
|
|
|
|
local function openWireless(st, d, isNews)
|
|
if isNews then
|
|
d.step("down")
|
|
d.step("a")
|
|
return
|
|
end
|
|
d.step("a")
|
|
d.waitFor(function() return st.state == Ui.STATE.SEARCHING end)
|
|
end
|
|
|
|
print("[test] 1. The main menu rows")
|
|
do
|
|
local noSave = Boot.new()
|
|
Boot.setHasContinue(noSave, false)
|
|
local rows = Boot.menuItems(noSave)
|
|
eq(#rows, 2, "no save file gives two rows")
|
|
eq(rows[1], "NEW GAME", "row 1 is NEW GAME")
|
|
|
|
local plain = Boot.new()
|
|
Boot.setHasContinue(plain, true)
|
|
Boot.setContinueInfo(plain, { name = "RED", mysteryGift = false })
|
|
rows = Boot.menuItems(plain)
|
|
eq(#rows, 4, "any save file gets the MYSTERY GIFT row")
|
|
eq(rows[3], "MYSTERY GIFT", "even without the passphrase flag")
|
|
eq(rows[4], "EXIT", "EXIT follows it")
|
|
check(Boot.hasMysteryGift(plain), "a save alone opens the Mystery Gift layout")
|
|
|
|
local gift = Boot.new()
|
|
Boot.setHasContinue(gift, true)
|
|
Boot.setContinueInfo(gift, { name = "RED", mysteryGift = true })
|
|
rows = Boot.menuItems(gift)
|
|
-- pokefirered/src/main_menu.c:370 MAIN_MENU_MYSTERYGIFT
|
|
eq(#rows, 4, "the Mystery Gift layout keeps EXIT as a fourth row")
|
|
eq(rows[1], "CONTINUE", "row 1 is CONTINUE")
|
|
eq(rows[2], "NEW GAME", "row 2 is NEW GAME")
|
|
eq(rows[3], "MYSTERY GIFT", "MYSTERY GIFT takes the third window")
|
|
eq(rows[4], "EXIT", "EXIT is always on the menu")
|
|
check(Boot.hasMysteryGift(gift), "the flag selects the Mystery Gift layout")
|
|
|
|
-- pokefirered/src/main_menu.c:21 enum MainMenuType
|
|
local sawOption = false
|
|
for _, state in ipairs({ noSave, plain, gift }) do
|
|
for _, row in ipairs(Boot.menuItems(state)) do
|
|
if row == "OPTION" then sawOption = true end
|
|
end
|
|
end
|
|
check(not sawOption, "no layout carries an OPTION row")
|
|
end
|
|
|
|
print("[test] 2. The flag comes off the save file")
|
|
do
|
|
local off = Boot.continueInfoFromSave({ name = "RED", flags = {} })
|
|
check(off.mysteryGift == false, "a save without the flag reads false")
|
|
local on = Boot.continueInfoFromSave({
|
|
name = "RED",
|
|
flags = { [tostring(FLAG_SYS_MYSTERY_GIFT_ENABLED)] = true },
|
|
})
|
|
check(on.mysteryGift == true, "FLAG_SYS_MYSTERY_GIFT_ENABLED reads true")
|
|
end
|
|
|
|
print("[test] 3. Picking MYSTERY GIFT reaches the front end")
|
|
do
|
|
local state = Boot.new()
|
|
Boot.setHasContinue(state, true)
|
|
Boot.setContinueInfo(state, { name = "RED", mysteryGift = true })
|
|
state.phase = Boot.PHASE.MENU
|
|
state.menuIndex = 3
|
|
state.fadeT, state.fadeTarget = 0, 0
|
|
local key = nil
|
|
local input = { wasPressed = function(_, k) return k == key end }
|
|
key = "a"
|
|
Boot.update(state, input, 1 / 60)
|
|
eq(state.fadeThen, "mystery_gift", "the MYSTERY GIFT row starts the fade")
|
|
key = nil
|
|
for _ = 1, 400 do
|
|
if state.phase == Boot.PHASE.MYSTERY_GIFT then break end
|
|
Boot.update(state, input, 1 / 60)
|
|
end
|
|
eq(state.phase, Boot.PHASE.MYSTERY_GIFT, "the fade hands over to the Mystery Gift screen")
|
|
check(type(state.gift) == "table", "a front-end state was built")
|
|
eq(state.gift.state, Ui.STATE.MAIN_MENU, "the front end opens on its own menu")
|
|
local okDraw, err = pcall(Boot.draw, state)
|
|
tcheck(okDraw, "the Mystery Gift screen draws: " .. tostring(err))
|
|
|
|
key = "b"
|
|
Boot.update(state, input, 1 / 60)
|
|
eq(state.phase, Boot.PHASE.MENU, "B leaves the front end for the main menu")
|
|
end
|
|
|
|
print("[test] 4. The front end receives a card and saves it")
|
|
local save, sess, st, saves
|
|
do
|
|
save = {}
|
|
sess = giftSession(save)
|
|
saves = 0
|
|
local feedTransport = okFeed()
|
|
st = Ui.new({
|
|
session = sess,
|
|
fetch = { transport = feedTransport },
|
|
onSave = function(s)
|
|
saves = saves + 1
|
|
return MysteryGift.applyToSave(s, save)
|
|
end,
|
|
})
|
|
|
|
local d = driver(st)
|
|
local step, finishMessage = d.step, d.finishMessage
|
|
|
|
-- pokefirered/src/mystery_gift_menu.c:197 sListMenuItems_CardsOrNews
|
|
local rows = Ui.mainRows()
|
|
teq(rows[1], "WONDER CARDS", "the front end opens on WONDER CARDS")
|
|
teq(rows[2], "WONDER NEWS", "WONDER NEWS is the second row")
|
|
teq(rows[3], "EXIT", "EXIT is the third row")
|
|
|
|
step("a")
|
|
eq(st.state, Ui.STATE.SEARCHING, "WONDER CARDS fetches the card list at once")
|
|
eq(feedTransport.calls, 1, "one request goes out")
|
|
eq(WirelessIcon.anim(), "searching", "the wireless icon plays its searching anim")
|
|
tcheck(type(st.prompt) == "string" and st.prompt:find("Searching for a WIRELESS"),
|
|
"with the cart's searching text")
|
|
d.waitFor(function() return st.state ~= Ui.STATE.SEARCHING end)
|
|
eq(st.state, Ui.STATE.OFFER_LIST, "the verified feed opens the card list")
|
|
eq(WirelessIcon.anim(), "3bars", "the icon shows the link")
|
|
local lm = ListStub.last
|
|
check(lm ~= nil and lm.opts.template.left == 1 and lm.opts.template.top == 3,
|
|
"the list sits at sWindowTemplate_GroupList")
|
|
eq(lm and #lm.items, 3, "every card in the feed is listed")
|
|
eq(lm and lm.items[1].label, "MYSTIC TICKET", "row 1 is the MYSTIC TICKET")
|
|
eq(lm and lm.items[2].label, "MEW", "row 2 is MEW")
|
|
eq(lm and lm.opts.maxShowed, 5, "five rows show at once")
|
|
step("a")
|
|
eq(st.state, Ui.STATE.GIFT_INPUT, "pressing a card shows it first")
|
|
eq(Ui.card(st).titleText, "MYSTIC TICKET", "the preview is the picked card")
|
|
check(not MysteryGift.validateSavedCard(sess), "a preview installs nothing")
|
|
local okDraw, err = pcall(Ui.draw, st)
|
|
tcheck(okDraw, "the preview draws: " .. tostring(err))
|
|
step("a")
|
|
eq(st.state, Ui.STATE.RESULT_MSG, "A receives it at once")
|
|
eq(WirelessIcon.anim(), nil, "the icon goes away when the link ends")
|
|
check(MysteryGift.validateSavedCard(sess), "the card is installed")
|
|
tcheck(st.msg ~= nil and tostring(st.msg.text):find("WONDER CARD"), "the received message names the card")
|
|
check(st.msg ~= nil and st.msg.hold == Ui.SUCCESS_FRAMES, "the success message holds for the fanfare")
|
|
eq(fanfares[#fanfares], 258, "MUS_OBTAIN_ITEM plays")
|
|
d.waitFor(function() return st.state == Ui.STATE.SAVE and not st.msg end)
|
|
eq(st.state, Ui.STATE.SAVE, "and the game saves")
|
|
step(nil)
|
|
eq(st.state, Ui.STATE.SAVE_DONE, "the save runs once")
|
|
eq(saves, 1, "onSave was called exactly once")
|
|
finishMessage()
|
|
eq(st.state, Ui.STATE.MAIN_MENU, "then back to the Mystery Gift menu")
|
|
|
|
check(MysteryGift.validateSavedCard(sess), "the card is on the session")
|
|
check(type(save.modData) == "table" and type(save.modData.mysteryGift) == "table",
|
|
"the record reached the save table")
|
|
check(save.flags[tostring(FLAG_SYS_MYSTERY_GIFT_ENABLED)] == true,
|
|
"FLAG_SYS_MYSTERY_GIFT_ENABLED reached the save table")
|
|
end
|
|
|
|
print("[test] 5. The list marks the held card and opens it")
|
|
do
|
|
local d = driver(st)
|
|
d.step("a")
|
|
eq(st.state, Ui.STATE.SEARCHING, "WONDER CARDS fetches again")
|
|
d.waitFor(function() return st.state ~= Ui.STATE.SEARCHING end)
|
|
eq(st.state, Ui.STATE.OFFER_LIST, "the list opens")
|
|
local lm = ListStub.last
|
|
-- pokefirered/src/union_room.c:4072
|
|
eq(lm and lm.items[1].colors, ListStub.COLOR_WHITE, "the MYSTIC TICKET shows as already had")
|
|
eq(lm and lm.items[2].colors, nil, "MEW does not")
|
|
d.step("a")
|
|
eq(st.state, Ui.STATE.GIFT_INPUT, "pressing the held card opens it")
|
|
local card = Ui.card(st)
|
|
eq(card.titleText, "MYSTIC TICKET", "the saved card is the MYSTIC TICKET")
|
|
eq(#card.bodyText, 4, "the card carries four body lines")
|
|
local okDraw, err = pcall(Ui.draw, st)
|
|
tcheck(okDraw, "the card view draws: " .. tostring(err))
|
|
d.step("b")
|
|
eq(st.state, Ui.STATE.OFFER_LIST, "B goes back to the list")
|
|
d.step("b")
|
|
eq(st.state, Ui.STATE.MAIN_MENU, "B on the list goes back to the menu")
|
|
check(MysteryGift.validateSavedCard(sess), "the held card stays")
|
|
end
|
|
|
|
print("[test] 6. Wonder News paging")
|
|
do
|
|
local body = {}
|
|
for i = 1, 10 do body[i] = "LINE " .. i end
|
|
local nst = Ui.new({ session = giftSession({}), onSave = function() return true end })
|
|
local keys = {}
|
|
local function pressed(k) return keys[k] == true end
|
|
local function step(k)
|
|
keys = {}
|
|
if k then keys[k] = true end
|
|
Ui.update(nst, pressed, 1 / 60)
|
|
end
|
|
nst.isNews = true
|
|
nst.viewNews = { id = 7, bgType = 1, titleText = "WONDER NEWS", bodyText = body }
|
|
nst.newsScroll = 0
|
|
nst.state = Ui.STATE.NEWS_VIEW
|
|
step("down")
|
|
eq(nst.newsScroll, 1, "down scrolls one line")
|
|
step("down")
|
|
eq(nst.newsScroll, 2, "down scrolls again")
|
|
step("down")
|
|
-- pokefirered/src/mystery_gift_show_news.c:346 scrollEnd counts lines past the eighth
|
|
eq(nst.newsScroll, 2, "ten lines over an eight-line window stop at two")
|
|
step("up")
|
|
eq(nst.newsScroll, 1, "up scrolls back")
|
|
local okDraw, err = pcall(Ui.draw, nst)
|
|
tcheck(okDraw, "the news view draws: " .. tostring(err))
|
|
step("b")
|
|
eq(nst.state, Ui.STATE.OFFER_LIST, "B goes back to the news list")
|
|
check(nst.viewNews == nil, "and drops the news it showed")
|
|
end
|
|
|
|
local function freshScreen(t, save)
|
|
save = save or {}
|
|
local sess2 = giftSession(save)
|
|
local st2 = Ui.new({
|
|
session = sess2,
|
|
fetch = { transport = t },
|
|
onSave = function(s) return MysteryGift.applyToSave(s, save) end,
|
|
})
|
|
return st2, driver(st2), sess2, save
|
|
end
|
|
|
|
local function searchResult(st2, d)
|
|
d.waitFor(function() return st2.state ~= Ui.STATE.SEARCHING end)
|
|
end
|
|
|
|
print("[test] 7. Wonder News over WIRELESS COMMUNICATION")
|
|
do
|
|
local st2, d, sess2 = freshScreen(okFeed())
|
|
openWireless(st2, d, true)
|
|
eq(st2.state, Ui.STATE.SEARCHING, "WONDER NEWS fetches the list at once")
|
|
searchResult(st2, d)
|
|
eq(st2.state, Ui.STATE.OFFER_LIST, "the news list opens")
|
|
eq(#ListStub.last.items, 1, "only news rows are listed")
|
|
eq(ListStub.last.items[1].label, "WONDER NEWS", "the news title is the row")
|
|
d.step("a")
|
|
eq(st2.state, Ui.STATE.NEWS_VIEW, "pressing a row opens that news")
|
|
eq(st2.viewNews and st2.viewNews.titleText, "WONDER NEWS", "the picked news is the one shown")
|
|
check(not MysteryGift.validateSavedNews(sess2), "reading saves nothing")
|
|
d.step("b")
|
|
eq(st2.state, Ui.STATE.OFFER_LIST, "B goes back to the list")
|
|
d.step("b")
|
|
eq(st2.state, Ui.STATE.MAIN_MENU, "B on the list goes back to the menu")
|
|
end
|
|
|
|
print("[test] 8. Cards you had before stay marked and can be switched back to")
|
|
do
|
|
local save = {}
|
|
local st2, d, sess2 = freshScreen(okFeed(), save)
|
|
openWireless(st2, d, false)
|
|
searchResult(st2, d)
|
|
d.step("down")
|
|
d.step("a")
|
|
d.step("a")
|
|
d.waitFor(function() return st2.state == Ui.STATE.MAIN_MENU and not st2.msg end)
|
|
eq(MysteryGift.getSavedCard(sess2).idNumber, 7, "the MEW card is installed")
|
|
local giftFlag = MysteryGift.receivedGiftFlag(MysteryGift.getSavedCard(sess2).flagId)
|
|
check(giftFlag ~= nil, "the MEW card has a received-gift flag")
|
|
MysteryGift.setFlag(sess2, giftFlag, true)
|
|
MysteryGift.clearCardAndRelated(sess2)
|
|
check(not MysteryGift.validateSavedCard(sess2), "then tossed")
|
|
|
|
openWireless(st2, d, false)
|
|
searchResult(st2, d)
|
|
eq(ListStub.last.items[2].colors, ListStub.COLOR_WHITE,
|
|
"the claimed card prints greyed in the list")
|
|
d.step("down")
|
|
d.step("a")
|
|
d.step("a")
|
|
d.waitFor(function() return st2.state == Ui.STATE.MAIN_MENU and not st2.msg end)
|
|
eq(MysteryGift.getSavedCard(sess2).idNumber, 7, "a card you had before installs again")
|
|
check(not MysteryGift.isGiftNotReceived(sess2), "and a gift already collected stays collected")
|
|
|
|
local reopened, d2, sess3 = freshScreen(okFeed(), save)
|
|
check(MysteryGift.hasClaimedCard(sess3, 7), "the claim was saved with the game")
|
|
openWireless(reopened, d2, false)
|
|
searchResult(reopened, d2)
|
|
eq(ListStub.last.items[2].colors, ListStub.COLOR_WHITE, "and still prints greyed after a reload")
|
|
d2.step("a")
|
|
d2.step("a")
|
|
d2.waitFor(function() return reopened.state == Ui.STATE.ASK_REPLACE end)
|
|
d2.step("a")
|
|
if reopened.state == Ui.STATE.ASK_REPLACE_UNRECEIVED then d2.step("a") end
|
|
d2.waitFor(function() return reopened.state == Ui.STATE.SAVE end)
|
|
eq(MysteryGift.getSavedCard(sess3).idNumber, 1, "switching to another card replaces the held one")
|
|
end
|
|
|
|
print("[test] 9. Replacing a held card asks first")
|
|
do
|
|
local st2, d, sess2 = freshScreen(okFeed())
|
|
MysteryGift.receiveCard(sess2, MysteryGift.builtins()[2].card)
|
|
d.step("a")
|
|
eq(st2.state, Ui.STATE.SEARCHING, "WONDER CARDS fetches the list")
|
|
searchResult(st2, d)
|
|
d.step("a")
|
|
d.step("a")
|
|
d.waitFor(function() return st2.state == Ui.STATE.ASK_REPLACE end)
|
|
check(st2.yesno ~= nil, "the cart's throw-away question is up")
|
|
d.step("a")
|
|
eq(st2.state, Ui.STATE.ASK_REPLACE_UNRECEIVED, "an uncollected gift asks again")
|
|
d.step("b")
|
|
eq(st2.state, Ui.STATE.OFFER_LIST, "declining goes back to the list")
|
|
eq(MysteryGift.getSavedCard(sess2).idNumber, 2, "the held card stays")
|
|
end
|
|
|
|
print("[test] 10. Offline, forged and empty feeds")
|
|
do
|
|
local st2, d, sess2 = freshScreen(transport({ status = "error", err = "could not connect" }))
|
|
openWireless(st2, d, false)
|
|
searchResult(st2, d)
|
|
eq(st2.state, Ui.STATE.RESULT_MSG, "no network ends the search")
|
|
eq(WirelessIcon.anim(), "error", "the icon shows the error")
|
|
tcheck(st2.msg ~= nil and tostring(st2.msg.text):find("Wireless Adapter"), "with the cart's not-connected text")
|
|
d.waitFor(function() return st2.state == Ui.STATE.MAIN_MENU end)
|
|
eq(st2.state, Ui.STATE.MAIN_MENU, "and it goes back to the menu")
|
|
eq(WirelessIcon.anim(), nil, "with the icon gone")
|
|
|
|
local body = FIXTURE_BODY:gsub('\\"item\\":370', '\\"item\\":371')
|
|
check(body ~= FIXTURE_BODY, "the forged body differs")
|
|
local forged, fd, fsess = freshScreen(transport({ status = "ok", code = 200, body = body }))
|
|
openWireless(forged, fd, false)
|
|
searchResult(forged, fd)
|
|
eq(forged.state, Ui.STATE.RESULT_MSG, "a forged feed ends the search")
|
|
eq(forged.lastError, "bad_signature", "because the signature failed")
|
|
tcheck(forged.msg ~= nil and tostring(forged.msg.text):find("error"), "with the cart's communication error")
|
|
check(not MysteryGift.validateSavedCard(fsess), "and nothing is installed")
|
|
fd.waitFor(function() return forged.state == Ui.STATE.MAIN_MENU and not forged.msg end)
|
|
eq(forged.state, Ui.STATE.MAIN_MENU, "back to the Mystery Gift menu")
|
|
|
|
MysteryGift.GIFT_PUBKEY = "2cecc61cc4d4ea70fc6802a66643e659a0f2c344eec6391ccf20b434ab280ffd"
|
|
local real, rd, rsess = freshScreen(okFeed())
|
|
openWireless(real, rd, false)
|
|
searchResult(real, rd)
|
|
eq(real.lastError, "bad_signature", "a feed not signed by the owner's key is refused")
|
|
check(not MysteryGift.validateSavedCard(rsess), "and installs nothing")
|
|
MysteryGift.GIFT_PUBKEY = FIXTURE_PUB
|
|
|
|
local noNews = [==[{"v":1,"payload":"{\"cards\":[],\"issued\":0,\"news\":[],\"v\":1}","sig":"4725a7934bfa21b943699b2b155d55235f598a7cc75531c4da36123848e296b590636ed33c3fcc7c4e19b0f604f5ea6e47fd5102676e365bfadfa5d6567a1c01"}]==]
|
|
MysteryGift.GIFT_PUBKEY = "6130adae42fe6c943b91dc721db1cc1ba2296de882f919b2380f6fc3a2f4cec8"
|
|
local empty, ed = freshScreen(transport({ status = "ok", code = 200, body = noNews }))
|
|
openWireless(empty, ed, true)
|
|
searchResult(empty, ed)
|
|
MysteryGift.GIFT_PUBKEY = FIXTURE_PUB
|
|
eq(empty.state, Ui.STATE.RESULT_MSG, "an empty news set ends the search")
|
|
-- pokefirered/src/union_room.c:2559
|
|
tcheck(empty.msg ~= nil and tostring(empty.msg.text):find("NEWS"), "with the cart's no-news-shared text")
|
|
ed.waitFor(function() return empty.state == Ui.STATE.MAIN_MENU end)
|
|
eq(empty.state, Ui.STATE.MAIN_MENU, "and it goes back to the menu")
|
|
|
|
local slow = transport({ status = "pending" })
|
|
local canceled, cd = freshScreen(slow)
|
|
openWireless(canceled, cd, false)
|
|
for _ = 1, 10 do cd.step(nil) end
|
|
cd.step("b")
|
|
check(slow.canceled == true, "B cancels the request")
|
|
eq(canceled.state, Ui.STATE.RESULT_MSG, "B stops the search")
|
|
tcheck(canceled.msg ~= nil and tostring(canceled.msg.text):find("canceled"), "with the cart's search-canceled text")
|
|
|
|
end
|
|
|
|
print("[test] 11. The save message runs the save with no button press")
|
|
do
|
|
local saves = 0
|
|
local st2 = Ui.new({
|
|
session = giftSession({}),
|
|
fetch = { transport = okFeed() },
|
|
onSave = function() saves = saves + 1 return true end,
|
|
})
|
|
local d = driver(st2)
|
|
local step = d.step
|
|
openWireless(st2, d, false)
|
|
searchResult(st2, d)
|
|
step("a")
|
|
step("a")
|
|
d.waitFor(function() return st2.state == Ui.STATE.RESULT_MSG end)
|
|
eq(st2.state, Ui.STATE.RESULT_MSG, "the card arrives")
|
|
for _ = 1, 1200 do
|
|
if st2.state ~= Ui.STATE.RESULT_MSG then break end
|
|
step(nil)
|
|
end
|
|
eq(st2.state, Ui.STATE.SAVE, "the save message is up without a button press")
|
|
-- pokefirered/src/mystery_gift_menu.c:860 SaveOnMysteryGiftMenu
|
|
for _ = 1, 600 do
|
|
if saves > 0 then break end
|
|
step(nil)
|
|
end
|
|
eq(saves, 1, "the save ran with no button press")
|
|
eq(st2.state, Ui.STATE.SAVE_DONE, "and the completed message follows")
|
|
tcheck(st2.msg ~= nil and tostring(st2.msg.text):find("press the A Button"),
|
|
"which is the one that waits for A")
|
|
end
|
|
|
|
print("[test] 12. EXIT stays on the menu under the MYSTERY GIFT row")
|
|
do
|
|
local gift = Boot.new()
|
|
Boot.setHasContinue(gift, true)
|
|
Boot.setContinueInfo(gift, { name = "RED", mysteryGift = true })
|
|
gift.phase = Boot.PHASE.MENU
|
|
gift.fadeT, gift.fadeTarget = 0, 0
|
|
local rows = Boot.menuItems(gift)
|
|
local sawExitRow = false
|
|
for _, row in ipairs(rows) do
|
|
if row == "EXIT" then sawExitRow = true end
|
|
end
|
|
check(sawExitRow, "the EXIT row is still there with MYSTERY GIFT on the menu")
|
|
local key = "select"
|
|
Boot.update(gift, { wasPressed = function(_, k) return k == key end }, 1 / 60)
|
|
check(gift.fadeThen ~= "exit", "SELECT is not a hidden exit")
|
|
for _ = 1, 3 do
|
|
key = "down"
|
|
Boot.update(gift, { wasPressed = function(_, k) return k == key end, isDown = function() return false end }, 1 / 60)
|
|
end
|
|
eq(gift.menuIndex, 4, "three downs reach the EXIT row")
|
|
check((gift.menuScroll or 0) > 0, "and the menu scrolled to show it")
|
|
key = "a"
|
|
Boot.update(gift, { wasPressed = function(_, k) return k == key end }, 1 / 60)
|
|
eq(gift.fadeThen, "exit", "A on EXIT starts the exit fade")
|
|
key = nil
|
|
local action = nil
|
|
for _ = 1, 400 do
|
|
action = Boot.update(gift, { wasPressed = function(_, k) return k == key end }, 1 / 60)
|
|
if action then break end
|
|
end
|
|
eq(type(action) == "table" and action.action or nil, "exit", "and it reaches the launcher exit action")
|
|
end
|
|
|
|
print("[test] 13. WONDER CARDS waits for the questionnaire passphrase")
|
|
do
|
|
local locked = Ui.new({ session = MysteryGift.sessionFromSave({}), onSave = function() return true end })
|
|
eq(#locked.rows, 2, "without the passphrase only WONDER NEWS and EXIT show")
|
|
teq(locked.rows[1], "WONDER NEWS", "row 1 is WONDER NEWS")
|
|
teq(locked.rows[2], "EXIT", "row 2 is EXIT")
|
|
Ui.update(locked, function(k) return k == "a" end, 1 / 60)
|
|
check(locked.isNews, "the first row opens the news branch")
|
|
eq(locked.state, Ui.STATE.SEARCHING, "which fetches the news list")
|
|
|
|
local open = Ui.new({ session = giftSession({}), onSave = function() return true end })
|
|
eq(#open.rows, 3, "the passphrase adds WONDER CARDS back")
|
|
teq(open.rows[1], "WONDER CARDS", "on the first row")
|
|
end
|
|
|
|
if failed == 0 then
|
|
print("PASS game3_gift_menu")
|
|
else
|
|
print("FAIL game3_gift_menu failures=" .. failed)
|
|
os.exit(1)
|
|
end
|