620 lines
16 KiB
Lua
620 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
|