Files
FlexLove/testing/__tests__/event_handler_test.lua
2025-11-19 12:14:58 -05:00

624 lines
16 KiB
Lua

-- Test suite for EventHandler module
package.path = package.path .. ";./?.lua;./modules/?.lua"
require("testing.loveStub")
local luaunit = require("testing.luaunit")
local EventHandler = require("modules.EventHandler")
local InputEvent = require("modules.InputEvent")
local utils = require("modules.utils")
TestEventHandler = {}
-- Mock Context module
local MockContext = {
getContext = function()
return {}
end,
}
-- Helper to create EventHandler with dependencies
local function createEventHandler(config)
config = config or {}
return EventHandler.new(config, {
InputEvent = InputEvent,
Context = MockContext,
utils = utils,
})
end
-- Mock element
local function createMockElement()
return {
x = 0,
y = 0,
width = 100,
height = 100,
disabled = false,
editable = false,
_focused = false,
padding = { left = 0, right = 0, top = 0, bottom = 0 },
_borderBoxWidth = 100,
_borderBoxHeight = 100,
isFocused = function(self)
return self._focused
end,
focus = function(self)
self._focused = true
end,
}
end
-- Test: new() creates instance with defaults
function TestEventHandler:test_new_creates_with_defaults()
local handler = createEventHandler()
luaunit.assertNotNil(handler)
luaunit.assertNil(handler.onEvent)
luaunit.assertNotNil(handler._pressed)
luaunit.assertEquals(handler._clickCount, 0)
luaunit.assertFalse(handler._hovered)
luaunit.assertFalse(handler._scrollbarPressHandled)
end
-- Test: new() accepts custom config
function TestEventHandler:test_new_accepts_custom_config()
local onEventCalled = false
local handler = createEventHandler({
onEvent = function()
onEventCalled = true
end,
_clickCount = 5,
_hovered = true,
})
luaunit.assertNotNil(handler.onEvent)
luaunit.assertEquals(handler._clickCount, 5)
luaunit.assertTrue(handler._hovered)
end
-- Test: initialize() sets element reference
function TestEventHandler:test_initialize_sets_element()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
luaunit.assertEquals(handler._element, element)
end
-- Test: getState() returns state data
function TestEventHandler:test_getState_returns_state()
local handler = createEventHandler({
_clickCount = 3,
_hovered = true,
})
handler._pressed[1] = true
handler._lastClickTime = 12345
local state = handler:getState()
luaunit.assertNotNil(state)
luaunit.assertEquals(state._clickCount, 3)
luaunit.assertTrue(state._hovered)
luaunit.assertTrue(state._pressed[1])
luaunit.assertEquals(state._lastClickTime, 12345)
end
-- Test: setState() restores state
function TestEventHandler:test_setState_restores_state()
local handler = createEventHandler()
local state = {
_pressed = { [1] = true },
_clickCount = 2,
_hovered = true,
_lastClickTime = 5000,
_lastClickButton = 1,
}
handler:setState(state)
luaunit.assertEquals(handler._clickCount, 2)
luaunit.assertTrue(handler._hovered)
luaunit.assertTrue(handler._pressed[1])
luaunit.assertEquals(handler._lastClickTime, 5000)
luaunit.assertEquals(handler._lastClickButton, 1)
end
-- Test: setState() handles nil gracefully
function TestEventHandler:test_setState_handles_nil()
local handler = createEventHandler()
handler._clickCount = 5
handler:setState(nil)
-- Should not error, should preserve original state
luaunit.assertEquals(handler._clickCount, 5)
end
-- Test: setState() uses defaults for missing values
function TestEventHandler:test_setState_uses_defaults()
local handler = createEventHandler()
handler:setState({}) -- Empty state
luaunit.assertNotNil(handler._pressed)
luaunit.assertEquals(handler._clickCount, 0)
luaunit.assertFalse(handler._hovered)
end
-- Test: resetScrollbarPressFlag() resets flag
function TestEventHandler:test_resetScrollbarPressFlag()
local handler = createEventHandler()
handler._scrollbarPressHandled = true
handler:resetScrollbarPressFlag()
luaunit.assertFalse(handler._scrollbarPressHandled)
end
-- Test: isAnyButtonPressed() returns false when no buttons pressed
function TestEventHandler:test_isAnyButtonPressed_returns_false()
local handler = createEventHandler()
luaunit.assertFalse(handler:isAnyButtonPressed())
end
-- Test: isAnyButtonPressed() returns true when button pressed
function TestEventHandler:test_isAnyButtonPressed_returns_true()
local handler = createEventHandler()
handler._pressed[1] = true
luaunit.assertTrue(handler:isAnyButtonPressed())
end
-- Test: isButtonPressed() checks specific button
function TestEventHandler:test_isButtonPressed_checks_specific_button()
local handler = createEventHandler()
handler._pressed[1] = true
handler._pressed[2] = false
luaunit.assertTrue(handler:isButtonPressed(1))
luaunit.assertFalse(handler:isButtonPressed(2))
luaunit.assertFalse(handler:isButtonPressed(3))
end
-- Test: processMouseEvents() returns early if no element
function TestEventHandler:test_processMouseEvents_no_element()
local handler = createEventHandler()
-- Should not error
handler:processMouseEvents(50, 50, true, true)
end
-- Test: processMouseEvents() handles press event
function TestEventHandler:test_processMouseEvents_press()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventReceived = nil
handler.onEvent = function(el, event)
eventReceived = event
end
-- Mock love.mouse.isDown for button 1
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1
end
-- First call - button just pressed
handler:processMouseEvents(50, 50, true, true)
luaunit.assertNotNil(eventReceived)
luaunit.assertEquals(eventReceived.type, "press")
luaunit.assertEquals(eventReceived.button, 1)
luaunit.assertTrue(handler._pressed[1])
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() handles drag event
function TestEventHandler:test_processMouseEvents_drag()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1
end
-- First call - press at (50, 50)
handler:processMouseEvents(50, 50, true, true)
-- Second call - drag to (60, 70)
handler:processMouseEvents(60, 70, true, true)
luaunit.assertTrue(#eventsReceived >= 2)
-- Find drag event
local dragEvent = nil
for _, event in ipairs(eventsReceived) do
if event.type == "drag" then
dragEvent = event
break
end
end
luaunit.assertNotNil(dragEvent, "Should receive drag event")
luaunit.assertEquals(dragEvent.dx, 10)
luaunit.assertEquals(dragEvent.dy, 20)
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() handles release and click
function TestEventHandler:test_processMouseEvents_release_and_click()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local isButtonDown = true
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1 and isButtonDown
end
-- Press
handler:processMouseEvents(50, 50, true, true)
-- Release
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
-- Should have: press, click, release events
luaunit.assertTrue(#eventsReceived >= 3)
local hasPress = false
local hasClick = false
local hasRelease = false
for _, event in ipairs(eventsReceived) do
if event.type == "press" then
hasPress = true
end
if event.type == "click" then
hasClick = true
end
if event.type == "release" then
hasRelease = true
end
end
luaunit.assertTrue(hasPress, "Should have press event")
luaunit.assertTrue(hasClick, "Should have click event")
luaunit.assertTrue(hasRelease, "Should have release event")
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() detects double-click
function TestEventHandler:test_processMouseEvents_double_click()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local isButtonDown = false
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1 and isButtonDown
end
-- First click
isButtonDown = true
handler:processMouseEvents(50, 50, true, true)
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
-- Second click (quickly after first)
isButtonDown = true
handler:processMouseEvents(50, 50, true, true)
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
-- Find click events
local clickEvents = {}
for _, event in ipairs(eventsReceived) do
if event.type == "click" then
table.insert(clickEvents, event)
end
end
luaunit.assertTrue(#clickEvents >= 2)
-- Second click should have clickCount = 2
if #clickEvents >= 2 then
luaunit.assertEquals(clickEvents[2].clickCount, 2)
end
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() handles rightclick
function TestEventHandler:test_processMouseEvents_rightclick()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local isButtonDown = false
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 2 and isButtonDown
end
-- Right click press and release
isButtonDown = true
handler:processMouseEvents(50, 50, true, true)
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
local hasRightClick = false
for _, event in ipairs(eventsReceived) do
if event.type == "rightclick" then
hasRightClick = true
luaunit.assertEquals(event.button, 2)
end
end
luaunit.assertTrue(hasRightClick, "Should have rightclick event")
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() handles middleclick
function TestEventHandler:test_processMouseEvents_middleclick()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local isButtonDown = false
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 3 and isButtonDown
end
-- Middle click press and release
isButtonDown = true
handler:processMouseEvents(50, 50, true, true)
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
local hasMiddleClick = false
for _, event in ipairs(eventsReceived) do
if event.type == "middleclick" then
hasMiddleClick = true
luaunit.assertEquals(event.button, 3)
end
end
luaunit.assertTrue(hasMiddleClick, "Should have middleclick event")
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() respects disabled state
function TestEventHandler:test_processMouseEvents_disabled()
local handler = createEventHandler()
local element = createMockElement()
element.disabled = true
handler:initialize(element)
local eventReceived = false
handler.onEvent = function(el, event)
eventReceived = true
end
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1
end
handler:processMouseEvents(50, 50, true, true)
-- Should not fire event for disabled element
luaunit.assertFalse(eventReceived)
love.mouse.isDown = originalIsDown
end
-- Test: processTouchEvents() handles touch
function TestEventHandler:test_processTouchEvents()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
-- Mock touch API
local originalGetTouches = love.touch.getTouches
local originalGetPosition = love.touch.getPosition
love.touch.getTouches = function()
return { "touch1" }
end
love.touch.getPosition = function(id)
if id == "touch1" then
return 150, 150 -- Outside element bounds
end
end
-- First call - touch starts inside
love.touch.getPosition = function(id)
if id == "touch1" then
return 50, 50 -- Inside element
end
end
handler:processTouchEvents()
-- Second call - touch moves outside
love.touch.getPosition = function(id)
if id == "touch1" then
return 150, 150 -- Outside element
end
end
handler:processTouchEvents()
-- Should receive touch event
luaunit.assertTrue(#eventsReceived >= 1)
love.touch.getTouches = originalGetTouches
love.touch.getPosition = originalGetPosition
end
-- Test: processTouchEvents() returns early if no element
function TestEventHandler:test_processTouchEvents_no_element()
local handler = createEventHandler()
-- Should not error
handler:processTouchEvents()
end
-- Test: processTouchEvents() returns early if no onEvent
function TestEventHandler:test_processTouchEvents_no_onEvent()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
-- Should not error (no onEvent callback)
handler:processTouchEvents()
end
-- Test: onEventDeferred flag defers callback execution
function TestEventHandler:test_onEventDeferred()
-- Mock FlexLove module
local deferredCallbacks = {}
local MockFlexLove = {
deferCallback = function(callback)
table.insert(deferredCallbacks, callback)
end,
}
package.loaded["FlexLove"] = MockFlexLove
local eventsReceived = {}
local handler = createEventHandler({
onEventDeferred = true,
onEvent = function(el, event)
table.insert(eventsReceived, event)
end,
})
local element = createMockElement()
handler:initialize(element)
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1
end
-- Press and release mouse button
handler:processMouseEvents(50, 50, true, true)
love.mouse.isDown = function()
return false
end
handler:processMouseEvents(50, 50, true, true)
-- Events should not be immediately executed
luaunit.assertEquals(#eventsReceived, 0)
-- Should have deferred callbacks queued
luaunit.assertTrue(#deferredCallbacks > 0)
-- Execute deferred callbacks
for _, callback in ipairs(deferredCallbacks) do
callback()
end
-- Now events should be received
luaunit.assertTrue(#eventsReceived > 0)
-- Check that we got a click event
local hasClick = false
for _, event in ipairs(eventsReceived) do
if event.type == "click" then
hasClick = true
break
end
end
luaunit.assertTrue(hasClick, "Should have received click event")
love.mouse.isDown = originalIsDown
package.loaded["FlexLove"] = nil
end
-- Test: onEventDeferred = false executes immediately
function TestEventHandler:test_onEventDeferred_false()
local eventsReceived = {}
local handler = createEventHandler({
onEventDeferred = false,
onEvent = function(el, event)
table.insert(eventsReceived, event)
end,
})
local element = createMockElement()
handler:initialize(element)
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1
end
-- Press and release mouse button
handler:processMouseEvents(50, 50, true, true)
love.mouse.isDown = function()
return false
end
handler:processMouseEvents(50, 50, true, true)
-- Events should be immediately executed
luaunit.assertTrue(#eventsReceived > 0)
-- Check that we got a click event
local hasClick = false
for _, event in ipairs(eventsReceived) do
if event.type == "click" then
hasClick = true
break
end
end
luaunit.assertTrue(hasClick, "Should have received click event")
love.mouse.isDown = originalIsDown
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end