test fixes

This commit is contained in:
bryanthaboi
2026-08-04 09:41:44 -04:00
parent b1350fdecd
commit dd4aface93
7 changed files with 66 additions and 28 deletions
+7
View File
@@ -348,6 +348,7 @@ function ImageData:getDimensions() return self.w, self.h end
function ImageData:getPixel() return 0, 0, 0, 1 end
function ImageData:setPixel() end
function ImageData:mapPixel() end
function ImageData:paste() end
function ImageData:encode() return { getString = function() return "" end } end
stub.image = {
@@ -362,6 +363,12 @@ stub.image = {
end,
}
-- Headless runs report the desktop OS so platform gates (GamepadMap's NX
-- check, the touch-overlay filter) take their desktop branch.
stub.system = {
getOS = function() return "OS X" end,
}
-- Desktop / headless: full-window safe area (matches LÖVE's fallback).
stub.window = {
getSafeArea = function()
+2 -1
View File
@@ -52,7 +52,8 @@ local function makeGame(party)
function stack:pop() return table.remove(self.states) end
function stack:top() return self.states[#self.states] end
return { data = Data, save = save, stack = stack,
input = { wasPressed = function() return true end } }
input = { wasPressed = function() return true end,
isDown = function() return true end } }
end
local function pump(battle, limit)
+4 -2
View File
@@ -283,7 +283,8 @@ end
do
local pressed = {}
local tb = freshBattle()
tb.game = { input = { wasPressed = function(_, k) return pressed[k] or false end },
tb.game = { input = { wasPressed = function(_, k) return pressed[k] or false end,
isDown = function(_, k) return pressed[k] or false end },
stack = { top = function() return tb end },
save = Game.save }
tb.kind = "wild"
@@ -359,7 +360,8 @@ do
local fg = {
data = Data,
save = require("src.core.SaveData").newGame(),
input = { wasPressed = function(_, k) return pressed[k] or false end },
input = { wasPressed = function(_, k) return pressed[k] or false end,
isDown = function(_, k) return pressed[k] or false end },
stack = stack,
}
fg.save.party = { Pokemon.new(Data, "BULBASAUR", 20) }
+2 -1
View File
@@ -38,7 +38,8 @@ local function makeGame(party)
function stack:pop() return table.remove(self.states) end
function stack:top() return self.states[#self.states] end
return { data = Data, save = save, stack = stack,
input = { wasPressed = function(_, b) return press[b] == true end } }
input = { wasPressed = function(_, b) return press[b] == true end,
isDown = function(_, b) return press[b] == true end } }
end
local function step(battle)
+2 -1
View File
@@ -44,7 +44,8 @@ local function makeGame(party)
function stack:pop() return table.remove(self.states) end
function stack:top() return self.states[#self.states] end
return { data = Data, save = save, stack = stack,
input = { wasPressed = function() return false end } }
input = { wasPressed = function() return false end,
isDown = function() return false end } }
end
local game = makeGame({ Pokemon.new(Data, "BULBASAUR", 50) })
+2 -1
View File
@@ -28,7 +28,8 @@ local function makeGame(species, level, moves)
function stack:pop() return table.remove(self.states) end
function stack:top() return self.states[#self.states] end
return { data = Data, save = save, stack = stack,
input = { wasPressed = function() return true end } }
input = { wasPressed = function() return true end,
isDown = function() return true end } }
end
local function pumpToMenu(battle)
+47 -22
View File
@@ -2631,7 +2631,13 @@ do
local popped = false
local og = { data = Data, save = SD.newGame(),
input = OInput, stack = { pop = function() popped = true end },
writeOptions = function(self) SD.saveOptions(self.save.options) end }
writeOptions = function(self) SD.saveOptions(self.save.options) end,
-- the PERFORMANCE row routes through Game:applyOptions; the
-- stub carries the headless slice of it (the tier record),
-- the display modules are re-applied at the end of the suite
applyOptions = function(self, o)
require("src.core.Performance").applyOptions(o)
end }
local om = OptionsMenu.new(og)
local function press(btn)
OInput.pressed = { [btn] = true }
@@ -2655,9 +2661,9 @@ do
"A switches the battle screen to the WIDE layout")
press("a")
eq(og.save.options.battleLayout, "og", "BATTLE LAYOUT wraps back to OG")
for _ = 1, 2 do press("down") end
eq(om.index, 6, "cursor reaches MUSIC VOL")
eq(om.scroll, 2, "viewport scrolls to keep MUSIC VOL on screen")
for _ = 1, 5 do press("down") end
eq(om.index, 9, "cursor reaches MUSIC VOL")
eq(om.scroll, 5, "viewport scrolls to keep MUSIC VOL on screen")
press("left")
eq(og.save.options.musicVol, 6, "left lowers MUSIC VOL")
press("right")
@@ -2672,25 +2678,33 @@ do
press("a")
eq(og.save.options.musicFilter, 0, "MUSIC FILTER wraps back to OFF")
press("down")
eq(om.index, 9, "cursor reaches COLORS")
eq(om.index, 12, "cursor reaches PERFORMANCE")
press("a")
eq(og.save.options.performance, "high", "A cycles PERFORMANCE to HIGH")
eq(require("src.core.Performance").tier, "high",
"the live tier tracks the PERFORMANCE option")
for _ = 1, 3 do press("a") end
eq(og.save.options.performance, "auto", "PERFORMANCE wraps back to AUTO")
press("down")
eq(om.index, 13, "cursor reaches COLORS")
press("a")
for _ = 1, 4 do press("a") end
press("down")
eq(om.index, 10, "cursor reaches TILT")
eq(om.index, 14, "cursor reaches TILT")
press("a")
eq(og.save.options.tilt, 1, "A cycles TILT to 15")
eq(Tilt.level, 1, "Tilt level tracks TILT option")
press("a"); press("a"); press("a")
eq(og.save.options.tilt, 0, "TILT wraps back to OFF")
press("down")
eq(om.index, 11, "cursor reaches GBC FX")
eq(om.index, 15, "cursor reaches GBC FX")
press("a")
eq(og.save.options.gbcfx, 1, "A cycles GBC FX to 1")
eq(GBCFX.level, 1, "GBCFX level tracks GBC FX option")
for _ = 1, 4 do press("a") end
eq(og.save.options.gbcfx, 0, "GBC FX wraps back to OFF")
press("down")
eq(om.index, 12, "cursor reaches ZOOM")
eq(om.index, 16, "cursor reaches ZOOM")
local ZoomOpt = require("src.render.Zoom")
press("a")
eq(og.save.options.zoom, 1, "A cycles ZOOM to IN1")
@@ -2698,7 +2712,7 @@ do
press("left")
eq(og.save.options.zoom, 0, "left steps ZOOM back to FIT")
press("down")
eq(om.index, 13, "cursor reaches VOID FILL")
eq(om.index, 17, "cursor reaches VOID FILL")
local TR = require("src.render.TileRenderer")
press("a")
eq(og.save.options.voidFill, "water", "A cycles VOID FILL to WATER")
@@ -2708,7 +2722,7 @@ do
press("a")
eq(og.save.options.voidFill, "trees", "VOID FILL wraps back to TREES")
press("down")
eq(om.index, 14, "cursor reaches VIDEO MODE")
eq(om.index, 18, "cursor reaches VIDEO MODE")
press("a")
eq(og.save.options.videoMode, "borderless",
"A cycles VIDEO MODE to BORDERLESS")
@@ -2716,7 +2730,9 @@ do
eq(og.save.options.videoMode, "windowed",
"VIDEO MODE wraps back to WINDOWED")
press("down")
eq(om.index, 15, "cursor reaches MAX FPS")
eq(om.index, 19, "cursor reaches FAITHFUL RATIO")
press("down")
eq(om.index, 20, "cursor reaches MAX FPS")
press("a")
eq(og.save.options.fpsCap, 75, "A cycles MAX FPS up from 60 to 75")
eq(FrameCap.current, 75, "the live render cap tracks the MAX FPS option")
@@ -2725,7 +2741,7 @@ do
for _ = 1, #FrameCap.STEPS - 1 do press("a") end
eq(og.save.options.fpsCap, 60, "MAX FPS wraps back to 60")
press("down")
eq(om.index, 16, "cursor reaches GAME SPEED")
eq(om.index, 21, "cursor reaches GAME SPEED")
press("a")
eq(og.save.options.speed, 2, "A cycles GAME SPEED to 2X")
-- Driven by the level list rather than a literal press count: adding a
@@ -2734,19 +2750,19 @@ do
for _ = 1, #GameSpeed.LEVELS - 1 do press("a") end
eq(og.save.options.speed, 1, "GAME SPEED wraps back to NORMAL")
press("down")
eq(om.index, 17, "cursor reaches MODS")
eq(om.index, 22, "cursor reaches MODS")
press("down")
eq(om.index, 18, "cursor reaches CONTROLS")
eq(om.index, 23, "cursor reaches CONTROLS")
press("down")
eq(om.index, 19, "CANCEL stays the fixed final row")
eq(om.scroll, 14, "CANCEL keeps the last option boxes on screen")
eq(om.index, 24, "CANCEL stays the fixed final row")
eq(om.scroll, 19, "CANCEL keeps the last option boxes on screen")
om:draw() -- smoke: scrolled layout draws under the headless stub
press("a")
check(popped, "A on CANCEL closes the options menu")
local om2 = OptionsMenu.new(og)
OInput.pressed = { up = true }; om2:update(1 / 60); OInput.pressed = {}
eq(om2.index, 19, "up from the top wraps to CANCEL")
eq(om2.scroll, 14, "wrapping to CANCEL scrolls to the tail")
eq(om2.index, 24, "up from the top wraps to CANCEL")
eq(om2.scroll, 19, "wrapping to CANCEL scrolls to the tail")
-- headless-safe: no love.audio, setters only update internal state
require("src.core.Music").applyOptions(og.save.options)
require("src.core.Sound").applyOptions(og.save.options)
@@ -2809,16 +2825,19 @@ do
menu:update(0)
eq(game.popCount(), 1, "Menu START-press closes when startCloses (start menu's PAD_START mask; no beep per HandleMenuInput_)")
-- both DisplayTwoOptionMenu branches hold 15 frames with the menu still
-- on screen before the answer lands (ChoiceBox.pending), so pump the
-- hold out after the press
game = stubGame({ a = true })
local yes
local box = ChoiceBox.new(game, function(v) yes = v end)
box:update(0)
for _ = 0, require("src.core.Timing").YES_NO_ANSWER do box:update(0) end
eq(yes, true, "ChoiceBox A on YES chooses true")
game = stubGame({ b = true })
local no
box = ChoiceBox.new(game, function(v) no = v end)
box:update(0)
for _ = 0, require("src.core.Timing").YES_NO_ANSWER do box:update(0) end
eq(no, false, "ChoiceBox B chooses false")
end
end
@@ -2837,7 +2856,8 @@ do
local qreturned = 0
local qg = {
data = Data, save = qsave, stack = qstack,
input = { wasPressed = function(_, k) return qpressed[k] end },
input = { wasPressed = function(_, k) return qpressed[k] end,
isDown = function(_, k) return qpressed[k] or false end },
returnToTitle = function() qreturned = qreturned + 1 end,
}
local qmenu = StartMenuQ.new(qg)
@@ -2858,7 +2878,12 @@ do
check(qbox ~= qmenu and qbox ~= nil and qbox.pages ~= nil,
"QUIT pushes a confirmation textbox")
eq(qbox.pages[1][1], "RETURN TO MAIN", "confirm asks RETURN TO MAIN MENU?")
qbox.onDone()
-- opts.choice: the box pushes the YES/NO itself once the last page has
-- typed out, so pump it rather than reaching for the old onDone hook
for _ = 1, 600 do
if qstack:top() ~= qbox then break end
qbox:update(1 / 60)
end
local qchoice = qstack:top()
check(qchoice ~= qbox and qchoice ~= nil and qchoice.onChoose ~= nil,
"textbox is followed by a YES/NO choice")