Druid-Extension/test/tests/test_input.lua
2025-04-17 19:18:40 +03:00

385 lines
11 KiB
Lua

return function()
describe("Input Component", function()
local mock_time
local mock_input
local druid_system
local druid
local context
before(function()
mock_time = require("deftest.mock.time")
mock_input = require("test.helper.mock_input")
druid_system = require("druid.druid")
mock_time.mock()
mock_time.set(0)
context = vmath.vector3()
druid = druid_system.new(context)
end)
after(function()
mock_time.unmock()
druid:final()
druid = nil
end)
it("Should create input component", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Initial Text")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
assert(input ~= nil)
assert(input.button ~= nil)
assert(input.text ~= nil)
assert(input:get_text() == "Initial Text")
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should select and unselect input", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Text")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
local on_input_select_calls = 0
local on_input_unselect_calls = 0
input.on_input_select:subscribe(function()
on_input_select_calls = on_input_select_calls + 1
end)
input.on_input_unselect:subscribe(function()
on_input_unselect_calls = on_input_unselect_calls + 1
end)
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
assert(input.is_selected == true)
assert(on_input_select_calls == 1)
-- Unselect input
druid:on_input(mock_input.click_pressed(200, 200))
druid:on_input(mock_input.click_released(200, 200))
assert(input.is_selected == false)
assert(on_input_unselect_calls == 1)
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should handle text input", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
local on_input_text_calls = 0
input.on_input_text:subscribe(function()
on_input_text_calls = on_input_text_calls + 1
end)
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate typing "Hello"
local function trigger_text_input(text)
return druid:on_input(hash("text"), {text = text})
end
-- Type "H"
trigger_text_input("H")
assert(input:get_text() == "H")
assert(on_input_text_calls == 1)
-- Type "e"
trigger_text_input("e")
assert(input:get_text() == "He")
assert(on_input_text_calls == 2)
-- Type "llo"
trigger_text_input("l")
trigger_text_input("l")
trigger_text_input("o")
assert(input:get_text() == "Hello")
assert(on_input_text_calls == 5)
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should handle backspace input", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Hello")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate backspace key
local function trigger_backspace()
return druid:on_input(hash("key_backspace"), {pressed = true})
end
-- Delete one letter
assert(trigger_backspace() == true)
assert(input:get_text() == "Hell")
-- Delete another letter
assert(trigger_backspace() == true)
assert(input:get_text() == "Hel")
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should set max length", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
local on_input_full_calls = 0
input.on_input_full:subscribe(function()
on_input_full_calls = on_input_full_calls + 1
end)
-- Set max length to 5
input:set_max_length(5)
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate typing text
local function trigger_text_input(text)
return druid:on_input(hash("text"), {text = text})
end
-- Type "Hello"
assert(trigger_text_input("Hello") == true)
assert(input:get_text() == "Hello")
assert(on_input_full_calls == 1)
-- Try to type "World" - should truncate
assert(trigger_text_input("World") == true)
assert(input:get_text() == "Hello")
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should validate allowed characters", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
local on_input_wrong_calls = 0
input.on_input_wrong:subscribe(function()
on_input_wrong_calls = on_input_wrong_calls + 1
end)
-- Set allowed characters to only numbers
input:set_allowed_characters("[0-9]")
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate typing text
local function trigger_text_input(text)
return druid:on_input(hash("text"), {text = text})
end
-- Type valid input "123"
assert(trigger_text_input("123") == true)
assert(input:get_text() == "123")
assert(on_input_wrong_calls == 0)
-- Type invalid input "abc" - should be rejected
assert(trigger_text_input("abc") == true)
assert(input:get_text() == "123")
assert(on_input_wrong_calls == 1)
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should handle password input", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "")
gui.set_font(text_node, "druid_text_bold")
-- Create password input
local input = druid:new_input(button_node, text_node, gui.KEYBOARD_TYPE_PASSWORD)
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate typing "Hello"
local function trigger_text_input(text)
return druid:on_input(hash("text"), {text = text})
end
assert(trigger_text_input("Hello") == true)
-- Raw text should be "Hello"
assert(input:get_text() == "Hello")
-- But displayed text should be "*****"
assert(gui.get_text(text_node) == "*****")
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should handle enter key", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Verify input is selected
assert(input.is_selected == true)
-- Simulate enter key press to unselect
assert(druid:on_input(hash("key_enter"), {released = true}) == true)
-- Verify input is unselected
assert(input.is_selected == false)
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should reset changes", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Initial")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Type some text
druid:on_input(hash("text"), {text = "M"})
druid:on_input(hash("text"), {text = "o"})
druid:on_input(hash("text"), {text = "d"})
assert(input:get_text() == "InitialMod")
-- Reset changes
input:reset_changes()
-- Verify text is reset to initial value
assert(input:get_text() == "Initial")
assert(input.is_selected == false)
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should handle selection and cursor manipulation", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Hello World")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
local cursor_changes = 0
input.on_select_cursor_change:subscribe(function()
cursor_changes = cursor_changes + 1
end)
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
assert(cursor_changes == 1)
-- Default cursor should be at the end
assert(input.cursor_index == 11) -- "Hello World" length
-- Move cursor to position 5
input:select_cursor(5)
assert(input.cursor_index == 5)
assert(cursor_changes == 2)
-- Move selection to the left by 1
input:move_selection(-1)
assert(input.cursor_index == 4)
assert(cursor_changes == 3)
-- Move selection to the right by 2
input:move_selection(2)
assert(input.cursor_index == 6)
assert(cursor_changes == 4)
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
it("Should handle empty input event", function()
local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))
local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Text")
gui.set_font(text_node, "druid_text_bold")
local input = druid:new_input(button_node, text_node)
local on_input_empty_calls = 0
input.on_input_empty:subscribe(function()
on_input_empty_calls = on_input_empty_calls + 1
end)
-- Select input
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Clear text
input:set_text("")
assert(on_input_empty_calls == 1)
assert(input.is_empty == true)
druid:remove(input)
gui.delete_node(button_node)
gui.delete_node(text_node)
end)
end)
end