Files
FlexLove/testing/__tests__/text_editor_test.lua
2025-11-15 02:47:26 -05:00

494 lines
13 KiB
Lua

-- Test suite for TextEditor module
package.path = package.path .. ";./?.lua;./modules/?.lua"
require("testing.loveStub")
local luaunit = require("testing.luaunit")
local TextEditor = require("modules.TextEditor")
local Color = require("modules.Color")
local utils = require("modules.utils")
TestTextEditor = {}
-- Mock dependencies
local MockContext = {
_immediateMode = false,
_focusedElement = nil,
}
local MockStateManager = {
getState = function(id)
return nil
end,
saveState = function(id, state) end,
}
-- Helper to create TextEditor with dependencies
local function createTextEditor(config)
config = config or {}
return TextEditor.new(config, {
Context = MockContext,
StateManager = MockStateManager,
Color = Color,
utils = utils,
})
end
-- Helper to create mock element
local function createMockElement()
return {
_stateId = "test-element-1",
width = 200,
height = 30,
}
end
-- Test: new() creates instance with defaults
function TestTextEditor:test_new_creates_with_defaults()
local editor = createTextEditor()
luaunit.assertNotNil(editor)
luaunit.assertFalse(editor.editable)
luaunit.assertFalse(editor.multiline)
luaunit.assertFalse(editor.passwordMode)
luaunit.assertEquals(editor.inputType, "text")
luaunit.assertEquals(editor._textBuffer, "")
luaunit.assertEquals(editor._cursorPosition, 0)
luaunit.assertFalse(editor._focused)
end
-- Test: new() accepts configuration
function TestTextEditor:test_new_accepts_config()
local editor = createTextEditor({
editable = true,
multiline = true,
passwordMode = true,
text = "Hello",
placeholder = "Enter text",
maxLength = 100,
inputType = "email",
})
luaunit.assertTrue(editor.editable)
luaunit.assertTrue(editor.multiline)
luaunit.assertTrue(editor.passwordMode)
luaunit.assertEquals(editor._textBuffer, "Hello")
luaunit.assertEquals(editor.placeholder, "Enter text")
luaunit.assertEquals(editor.maxLength, 100)
luaunit.assertEquals(editor.inputType, "email")
end
-- Test: new() sanitizes initial text
function TestTextEditor:test_new_sanitizes_initial_text()
local editor = createTextEditor({
text = "Hello\n\nWorld",
multiline = false,
allowNewlines = false,
})
-- Newlines should be removed for single-line
luaunit.assertNotEquals(editor._textBuffer, "Hello\n\nWorld")
end
-- Test: initialize() sets element reference
function TestTextEditor:test_initialize_sets_element()
local editor = createTextEditor()
local element = createMockElement()
editor:initialize(element)
luaunit.assertEquals(editor._element, element)
end
-- Test: getText() returns current text
function TestTextEditor:test_getText_returns_text()
local editor = createTextEditor({ text = "Hello World" })
luaunit.assertEquals(editor:getText(), "Hello World")
end
-- Test: getText() returns empty string for nil buffer
function TestTextEditor:test_getText_returns_empty_for_nil()
local editor = createTextEditor()
editor._textBuffer = nil
luaunit.assertEquals(editor:getText(), "")
end
-- Test: setText() updates text buffer
function TestTextEditor:test_setText_updates_buffer()
local editor = createTextEditor()
editor:setText("New text")
luaunit.assertEquals(editor:getText(), "New text")
end
-- Test: setText() sanitizes text by default
function TestTextEditor:test_setText_sanitizes()
local editor = createTextEditor({
multiline = false,
allowNewlines = false,
})
editor:setText("Line1\nLine2")
-- Should remove newlines for single-line
local text = editor:getText()
luaunit.assertFalse(text:find("\n") ~= nil)
end
-- Test: setText() skips sanitization when requested
function TestTextEditor:test_setText_skips_sanitization()
local editor = createTextEditor({
multiline = false,
allowNewlines = false,
})
editor:setText("Line1\nLine2", true) -- skipSanitization = true
luaunit.assertEquals(editor:getText(), "Line1\nLine2")
end
-- Test: insertText() adds text at position
function TestTextEditor:test_insertText_at_position()
local editor = createTextEditor({ text = "Hello" })
editor:insertText(" World", 5)
luaunit.assertEquals(editor:getText(), "Hello World")
end
-- Test: insertText() adds text at start
function TestTextEditor:test_insertText_at_start()
local editor = createTextEditor({ text = "World" })
editor:insertText("Hello ", 0)
luaunit.assertEquals(editor:getText(), "Hello World")
end
-- Test: deleteText() removes text range
function TestTextEditor:test_deleteText_removes_range()
local editor = createTextEditor({ text = "Hello World" })
editor:deleteText(5, 11) -- Remove " World"
luaunit.assertEquals(editor:getText(), "Hello")
end
-- Test: deleteText() handles reversed positions
function TestTextEditor:test_deleteText_handles_reversed()
local editor = createTextEditor({ text = "Hello World" })
editor:deleteText(11, 5) -- Reversed: should swap
luaunit.assertEquals(editor:getText(), "Hello")
end
-- Test: replaceText() replaces range with new text
function TestTextEditor:test_replaceText_replaces_range()
local editor = createTextEditor({ text = "Hello World" })
editor:replaceText(6, 11, "Lua")
luaunit.assertEquals(editor:getText(), "Hello Lua")
end
-- Test: setCursorPosition() sets cursor
function TestTextEditor:test_setCursorPosition()
local editor = createTextEditor({ text = "Hello" })
editor:setCursorPosition(3)
luaunit.assertEquals(editor:getCursorPosition(), 3)
end
-- Test: setCursorPosition() clamps to valid range
function TestTextEditor:test_setCursorPosition_clamps()
local editor = createTextEditor({ text = "Hello" })
editor:setCursorPosition(100) -- Beyond text length
luaunit.assertEquals(editor:getCursorPosition(), 5)
end
-- Test: moveCursorBy() moves cursor relative
function TestTextEditor:test_moveCursorBy()
local editor = createTextEditor({ text = "Hello" })
editor:setCursorPosition(2)
editor:moveCursorBy(2)
luaunit.assertEquals(editor:getCursorPosition(), 4)
end
-- Test: moveCursorToStart() moves to beginning
function TestTextEditor:test_moveCursorToStart()
local editor = createTextEditor({ text = "Hello" })
editor:setCursorPosition(3)
editor:moveCursorToStart()
luaunit.assertEquals(editor:getCursorPosition(), 0)
end
-- Test: moveCursorToEnd() moves to end
function TestTextEditor:test_moveCursorToEnd()
local editor = createTextEditor({ text = "Hello" })
editor:moveCursorToEnd()
luaunit.assertEquals(editor:getCursorPosition(), 5)
end
-- Test: setSelection() sets selection range
function TestTextEditor:test_setSelection()
local editor = createTextEditor({ text = "Hello World" })
editor:setSelection(0, 5)
local start, endPos = editor:getSelection()
luaunit.assertEquals(start, 0)
luaunit.assertEquals(endPos, 5)
end
-- Test: hasSelection() returns true when selected
function TestTextEditor:test_hasSelection_true()
local editor = createTextEditor({ text = "Hello" })
editor:setSelection(0, 5)
luaunit.assertTrue(editor:hasSelection())
end
-- Test: hasSelection() returns false when no selection
function TestTextEditor:test_hasSelection_false()
local editor = createTextEditor({ text = "Hello" })
luaunit.assertFalse(editor:hasSelection())
end
-- Test: clearSelection() removes selection
function TestTextEditor:test_clearSelection()
local editor = createTextEditor({ text = "Hello" })
editor:setSelection(0, 5)
editor:clearSelection()
luaunit.assertFalse(editor:hasSelection())
end
-- Test: getSelectedText() returns selected text
function TestTextEditor:test_getSelectedText()
local editor = createTextEditor({ text = "Hello World" })
editor:setSelection(0, 5)
luaunit.assertEquals(editor:getSelectedText(), "Hello")
end
-- Test: deleteSelection() removes selected text
function TestTextEditor:test_deleteSelection()
local editor = createTextEditor({ text = "Hello World" })
editor:setSelection(0, 6)
editor:deleteSelection()
luaunit.assertEquals(editor:getText(), "World")
luaunit.assertFalse(editor:hasSelection())
end
-- Test: selectAll() selects entire text
function TestTextEditor:test_selectAll()
local editor = createTextEditor({ text = "Hello World" })
editor:selectAll()
local start, endPos = editor:getSelection()
luaunit.assertEquals(start, 0)
luaunit.assertEquals(endPos, 11)
end
-- Test: sanitization with maxLength
function TestTextEditor:test_sanitize_max_length()
local editor = createTextEditor({
maxLength = 5,
})
editor:setText("HelloWorld")
luaunit.assertEquals(editor:getText(), "Hello")
end
-- Test: sanitization disabled
function TestTextEditor:test_sanitization_disabled()
local editor = createTextEditor({
sanitize = false,
multiline = false,
allowNewlines = false,
})
editor:setText("Line1\nLine2")
-- Should NOT sanitize newlines when disabled
luaunit.assertEquals(editor:getText(), "Line1\nLine2")
end
-- Test: customSanitizer callback
function TestTextEditor:test_custom_sanitizer()
local editor = createTextEditor({
customSanitizer = function(text)
return text:upper()
end,
})
editor:setText("hello")
luaunit.assertEquals(editor:getText(), "HELLO")
end
-- Test: allowNewlines follows multiline setting
function TestTextEditor:test_allowNewlines_follows_multiline()
local editor = createTextEditor({
multiline = true,
})
luaunit.assertTrue(editor.allowNewlines)
editor = createTextEditor({
multiline = false,
})
luaunit.assertFalse(editor.allowNewlines)
end
-- Test: allowNewlines can be overridden
function TestTextEditor:test_allowNewlines_override()
local editor = createTextEditor({
multiline = true,
allowNewlines = false,
})
luaunit.assertFalse(editor.allowNewlines)
end
-- Test: allowTabs defaults to true
function TestTextEditor:test_allowTabs_default()
local editor = createTextEditor()
luaunit.assertTrue(editor.allowTabs)
end
-- Test: cursorBlinkRate default
function TestTextEditor:test_cursorBlinkRate_default()
local editor = createTextEditor()
luaunit.assertEquals(editor.cursorBlinkRate, 0.5)
end
-- Test: selectOnFocus default
function TestTextEditor:test_selectOnFocus_default()
local editor = createTextEditor()
luaunit.assertFalse(editor.selectOnFocus)
end
-- Test: onSanitize callback triggered when text is sanitized
function TestTextEditor:test_onSanitize_callback()
local callbackCalled = false
local originalText = nil
local sanitizedText = nil
local editor = createTextEditor({
maxLength = 5,
onSanitize = function(element, original, sanitized)
callbackCalled = true
originalText = original
sanitizedText = sanitized
end,
})
local mockElement = createMockElement()
editor:initialize(mockElement)
-- Insert text that exceeds maxLength
editor:_sanitizeText("This is a long text that exceeds max length")
luaunit.assertTrue(callbackCalled)
luaunit.assertEquals(originalText, "This is a long text that exceeds max length")
luaunit.assertEquals(sanitizedText, "This ")
end
-- Test: initialize with immediate mode and existing state
function TestTextEditor:test_initialize_immediate_mode_with_state()
local mockStateManager = {
getState = function(id)
return {
_focused = true,
_textBuffer = "restored text",
_cursorPosition = 10,
_selectionStart = 2,
_selectionEnd = 5,
_cursorBlinkTimer = 0.3,
_cursorVisible = false,
_cursorBlinkPaused = true,
_cursorBlinkPauseTimer = 1.0,
}
end,
saveState = function(id, state) end,
}
local mockContext = {
_immediateMode = true,
_focusedElement = nil,
}
local editor = TextEditor.new({}, {
Context = mockContext,
StateManager = mockStateManager,
Color = Color,
utils = utils,
})
local mockElement = createMockElement()
editor:initialize(mockElement)
-- State should be fully restored
luaunit.assertEquals(editor._textBuffer, "restored text")
luaunit.assertEquals(editor._cursorPosition, 10)
luaunit.assertEquals(editor._selectionStart, 2)
luaunit.assertEquals(editor._selectionEnd, 5)
luaunit.assertEquals(editor._cursorBlinkTimer, 0.3)
luaunit.assertEquals(editor._cursorVisible, false)
luaunit.assertEquals(editor._cursorBlinkPaused, true)
luaunit.assertEquals(editor._cursorBlinkPauseTimer, 1.0)
luaunit.assertTrue(editor._focused)
luaunit.assertEquals(mockContext._focusedElement, mockElement)
end
-- Test: customSanitizer function
function TestTextEditor:test_customSanitizer()
local editor = createTextEditor({
customSanitizer = function(text)
return text:upper()
end,
})
local result = editor:_sanitizeText("hello world")
luaunit.assertEquals(result, "HELLO WORLD")
end
-- Test: sanitize disabled
function TestTextEditor:test_sanitize_disabled()
local editor = createTextEditor({
sanitize = false,
maxLength = 5,
})
local result = editor:_sanitizeText("This is a very long text")
-- Should not be truncated since sanitize is false
luaunit.assertEquals(result, "This is a very long text")
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end