Files
gen1recomp/tests/engine/sdl_controller_support_test.lua
T

295 lines
9.6 KiB
Lua

-- luajit tests/engine/sdl_controller_support_test.lua
package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
local check, eq = T.check, T.eq
love = love or require("tests.love_stub")
local Input = require("src.core.Input")
local GamepadMap = require("src.core.GamepadMap")
local BindingsMenu = require("src.ui.BindingsMenu")
local Game = require("src.core.Game")
local pad = { isGamepad = function() return true end }
local function newGame()
local game = { save = { options = {} }, data = {}, wroteOptions = 0 }
game.stack = {
states = {},
push = function(self, s) table.insert(self.states, s) end,
pop = function(self) return table.remove(self.states) end,
top = function(self) return self.states[#self.states] end,
}
game.input = Input
function game:writeOptions() self.wroteOptions = self.wroteOptions + 1 end
function game:_cycleSpeed(dir) self.cycledSpeed = (self.cycledSpeed or 0) + dir end
return game
end
Input:init()
Input:reset()
Input:gamepadaxis(pad, "leftx", -0.9)
Input:step()
check(Input:wasPressed("left"), "left stick left presses left")
check(Input:isDown("left"), "left stick left holds left")
Input:gamepadaxis(pad, "leftx", 0)
check(not Input:isDown("left"), "centering left stick releases left")
Input:reset()
Input:gamepadaxis(pad, "lefty", -0.8)
Input:step()
check(Input:wasPressed("up"), "left stick up presses up")
check(Input:isDown("up"), "left stick up holds up")
Input:gamepadaxis(pad, "lefty", 0)
check(not Input:isDown("up"), "centering left stick releases up")
Input:reset()
Input:gamepadaxis(pad, "rightx", 0.9)
Input:step()
check(Input:wasPressed("right"), "right stick right presses right")
check(Input:isDown("right"), "right stick right holds right")
Input:gamepadaxis(pad, "rightx", 0)
check(not Input:isDown("right"), "centering right stick releases right")
Input:reset()
Input:gamepadaxis(pad, "righty", 0.8)
Input:step()
check(Input:wasPressed("down"), "right stick down presses down")
check(Input:isDown("down"), "right stick down holds down")
Input:gamepadaxis(pad, "righty", 0)
check(not Input:isDown("down"), "centering right stick releases down")
Input:reset()
Input:gamepadaxis(pad, "lefty", -0.4)
check(not Input:isDown("up"), "lefty -0.4 is below STICK_ON (0.5), does not trigger")
Input:gamepadaxis(pad, "lefty", -0.7)
check(Input:isDown("up"), "lefty -0.7 triggers up")
Input:gamepadaxis(pad, "lefty", -0.4)
check(Input:isDown("up"), "lefty -0.4 stays held above STICK_OFF (0.3)")
Input:gamepadaxis(pad, "lefty", -0.2)
check(not Input:isDown("up"), "lefty -0.2 drops below STICK_OFF (0.3), releases up")
Input:reset()
Input:gamepadaxis(pad, "leftx", 0.9)
Input:step()
check(Input:isDown("right"), "stick tilted right")
check(not Input:isDown("down"), "down not held")
Input:gamepadaxis(pad, "lefty", 0.95)
Input:step()
check(not Input:isDown("right"), "rolling to down releases right")
check(Input:isDown("down"), "and presses down")
Input:gamepadaxis(pad, "leftx", 0)
Input:gamepadaxis(pad, "lefty", 0)
check(not Input:isDown("down"), "centering releases down")
Input:reset()
Input:gamepadpressed(pad, "dpup")
Input:gamepadaxis(pad, "lefty", -0.9)
Input:step()
check(Input:isDown("up"), "both D-pad and stick hold up")
Input:gamepadreleased(pad, "dpup")
check(Input:isDown("up"), "releasing D-pad still keeps up held via stick")
Input:gamepadaxis(pad, "lefty", 0)
check(not Input:isDown("up"), "releasing stick finally clears up")
Input:reset()
local name, phase = Input:triggerAxis("triggerleft", 0.3)
check(phase == nil, "trigger at 0.3 is below threshold")
name, phase = Input:triggerAxis("triggerleft", 0.6)
eq(phase, "pressed", "trigger at 0.6 fires pressed")
name, phase = Input:triggerAxis("triggerleft", 0.3)
check(phase == nil, "trigger releasing to 0.3 stays held (hysteresis)")
name, phase = Input:triggerAxis("triggerleft", 0.1)
eq(phase, "released", "trigger dropping to 0.1 fires released")
local game = newGame()
local bm = BindingsMenu.new(game)
game.stack:push(bm)
bm.index = 5
bm.onChoose(bm.items[5])
check(bm.capture == bm.items[5], "A row capture armed")
bm:onGamepadPressed("triggerright")
check(game.save.options.bindings == nil, "pending trigger release")
bm:onGamepadReleased("triggerright")
local bindings = game.save.options.bindings
eq(bindings.a.pad, "triggerright", "triggerright stored on row A")
eq(bm.items[5].right, "Z/R2", "row A displays Z/R2")
Input:applyBindings(bindings)
Input:reset()
Input:gamepadaxis(pad, "triggerright", 0.8)
Input:step()
check(Input:isDown("a"), "pulling R2 presses A")
Input:gamepadaxis(pad, "triggerright", 0)
check(not Input:isDown("a"), "releasing R2 releases A")
bm.index = 1
bm.onChoose(bm.items[1])
bm:onGamepadPressed("leftstick_up")
bm:onGamepadReleased("leftstick_up")
eq(bindings.up.pad, "leftstick_up", "leftstick_up stored on row UP")
eq(bm.items[1].right, "UP/LS-UP", "row UP displays UP/LS-UP")
bm.index = 2
bm.onChoose(bm.items[2])
bm:onGamepadPressed("rightstick_down")
bm:onGamepadReleased("rightstick_down")
eq(bindings.down.pad, "rightstick_down", "rightstick_down stored on row DOWN")
eq(bm.items[2].right, "DOWN/RS-DN", "row DOWN displays DOWN/RS-DN")
bm.index = 10
bm.onChoose(bm.items[10])
bm:onGamepadPressed("rightstick")
bm:onGamepadReleased("rightstick")
eq(bindings.speedUp.pad, "rightstick", "rightstick stored on SPEED +")
eq(bm.items[10].right, "1/RS", "row SPEED + displays 1/RS")
Input:applyBindings(bindings)
eq(Input:padAction("rightstick"), "speedUp", "rightstick triggers speedUp action")
bm.index = 9
bm.onChoose(bm.items[9])
bm:onGamepadPressed("triggerleft")
bm:onGamepadReleased("triggerleft")
eq(bindings.speedDown.pad, "triggerleft", "triggerleft stored on SPEED -")
eq(bm.items[9].right, "0/L2", "row SPEED - displays 0/L2")
Input:applyBindings(bindings)
eq(Input:padAction("triggerleft"), "speedDown", "triggerleft triggers speedDown action")
local gameInstance = setmetatable(newGame(), { __index = Game })
local bm2 = BindingsMenu.new(gameInstance)
gameInstance.stack:push(bm2)
bm2.index = 6
bm2.onChoose(bm2.items[6])
check(bm2.capture == bm2.items[6], "Row B capture armed")
Game.gamepadaxis(gameInstance, pad, "rightx", -0.8)
check(bm2.pending ~= nil and bm2.pending.value == "rightstick_left",
"Game:gamepadaxis routes stick tilt into capture as rightstick_left")
Game.gamepadaxis(gameInstance, pad, "rightx", 0)
check(bm2.capture == nil, "centering stick completes capture")
eq(gameInstance.save.options.bindings.b.pad, "rightstick_left", "Row B bound to rightstick_left")
eq(bm2.items[6].right, "X/RS-LT", "Row B displays X/RS-LT")
local bm3 = BindingsMenu.new(game)
game.stack:push(bm3)
bm3.index = 5
bm3.onChoose(bm3.items[5])
bm3:onGamepadPressed("leftstick")
bm3:onGamepadReleased("leftstick")
eq(bm3.items[5].right, "Z/LS", "Row A bound to leftstick shows Z/LS")
bm3.index = 6
bm3.onChoose(bm3.items[6])
bm3:onGamepadPressed("x")
bm3:onGamepadReleased("x")
eq(bm3.items[6].right, "X/X", "Row B bound to x shows X/X")
bm3.index = 7
bm3.onChoose(bm3.items[7])
bm3:onGamepadPressed("guide")
bm3:onGamepadReleased("guide")
eq(bm3.items[7].right, "ESC/GUIDE", "Row START bound to guide shows ESC/GUIDE")
bm3.index = 8
bm3.onChoose(bm3.items[8])
bm3:onGamepadPressed("touchpad")
bm3:onGamepadReleased("touchpad")
eq(bm3.items[8].right, "TAB/PAD", "Row SELECT bound to touchpad shows TAB/PAD")
bm3.index = 5
bm3.onSelectKey(bm3.items[5])
eq(bm3.items[5].right, "Z/A", "clearing row A restores default Z/A")
game.save.options.bindings = {
a = { pad = "leftstick" },
b = { pad = "rightstick_up" },
up = { pad = "triggerright" },
}
bm3.confirmReset(bm3)
local confirmBox = game.stack:top()
check(confirmBox ~= nil, "confirm reset dialog pushed")
if confirmBox and confirmBox.onChoose then confirmBox.onChoose(true) end
check(game.save.options.bindings == nil, "reset all cleared options.bindings")
local Game2 = require("src.core.Game2")
local Game3 = require("src.core.Game3")
local g2 = setmetatable(newGame(), { __index = Game2 })
local bmG2 = BindingsMenu.new(g2)
g2.stack:push(bmG2)
bmG2.index = 5
bmG2.onChoose(bmG2.items[5])
Game2.gamepadaxis(g2, pad, "lefty", -0.9)
check(bmG2.pending ~= nil and bmG2.pending.value == "leftstick_up",
"Game2:gamepadaxis routes stick tilt into menu capture")
Game2.gamepadaxis(g2, pad, "lefty", 0)
check(bmG2.capture == nil, "Game2 stick release completes capture")
eq(bmG2.items[5].right, "Z/LS-UP", "Game2 row A displays Z/LS-UP")
local g3 = setmetatable(newGame(), { __index = Game3 })
g3.input = Input
Input:reset()
Input:armCapture()
Game3.gamepadaxis(g3, pad, "righty", 0.9)
local capEvents = Input:takeCaptureEvents()
check(capEvents ~= nil and #capEvents > 0, "Game3:gamepadaxis records captureEvents")
check(capEvents[1].kind == "pad" and capEvents[1].phase == "pressed" and capEvents[1].value == "rightstick_down",
"Game3 capture event is rightstick_down pressed")
Game3.gamepadaxis(g3, pad, "righty", 0)
local relEvents = Input:takeCaptureEvents()
check(relEvents ~= nil and #relEvents > 0 and relEvents[1].phase == "released" and relEvents[1].value == "rightstick_down",
"Game3 capture event is rightstick_down released")
Input:disarmCapture()
local mockPad = {
isGamepad = function() return true end,
isGamepadDown = function(_, b) return false end,
getGamepadAxis = function(_, axis)
if axis == "triggerleft" then return 0.9 end
if axis == "lefty" then return -0.9 end
return 0
end,
}
Input:init()
Input:applyBindings({
speedDown = { pad = "triggerleft" },
up = { pad = "leftstick_up" },
})
Input:reconcile()
Input:gamepadaxis(mockPad, "triggerleft", 0.9)
Input:gamepadaxis(mockPad, "lefty", -0.9)
Input:step()
check(Input:isDown("up"), "reconciled stick axis holds up")
Input:init()
T.finish("sdl_controller_support_test")