From a1a4ebc4b1d08e576cd00f98313b8cbb6acec596 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Fri, 14 Nov 2025 23:13:34 -0500 Subject: [PATCH] merging tests --- modules/Element.lua | 71 ++ testing/__tests__/element_di_test.lua | 186 ----- testing/__tests__/element_test.lua | 704 +++++++++++++++++- .../layout_engine_integration_test.lua | 441 ----------- testing/__tests__/layout_engine_test.lua | 64 +- testing/__tests__/sanitization_test.lua | 293 ++++++++ .../texteditor_sanitization_test.lua | 308 -------- testing/__tests__/theme_core_test.lua | 302 -------- ...eme_validation_test.lua => theme_test.lua} | 297 +++++++- testing/runAll.lua | 10 +- 10 files changed, 1422 insertions(+), 1254 deletions(-) delete mode 100644 testing/__tests__/element_di_test.lua delete mode 100644 testing/__tests__/layout_engine_integration_test.lua delete mode 100644 testing/__tests__/texteditor_sanitization_test.lua delete mode 100644 testing/__tests__/theme_core_test.lua rename testing/__tests__/{theme_validation_test.lua => theme_test.lua} (65%) diff --git a/modules/Element.lua b/modules/Element.lua index ca072ff..7c61eb8 100644 --- a/modules/Element.lua +++ b/modules/Element.lua @@ -376,6 +376,9 @@ function Element.new(props, deps) end self.opacity = props.opacity or 1 + -- Set visibility property (default: "visible") + self.visibility = props.visibility or "visible" + -- Handle cornerRadius (can be number or table) if props.cornerRadius then if type(props.cornerRadius) == "number" then @@ -1689,6 +1692,74 @@ function Element:addChild(child) end end +--- Remove a specific child from this element +---@param child Element +function Element:removeChild(child) + for i, c in ipairs(self.children) do + if c == child then + table.remove(self.children, i) + child.parent = nil + + -- Recalculate auto-sizing if needed + if self.autosizing.width or self.autosizing.height then + if self.autosizing.width then + local contentWidth = self:calculateAutoWidth() + self._borderBoxWidth = contentWidth + self.padding.left + self.padding.right + self.width = contentWidth + end + if self.autosizing.height then + local contentHeight = self:calculateAutoHeight() + self._borderBoxHeight = contentHeight + self.padding.top + self.padding.bottom + self.height = contentHeight + end + end + + -- Re-layout children after removal + if not self._deps.Context._immediateMode then + self:layoutChildren() + end + + break + end + end +end + +--- Remove all children from this element +function Element:clearChildren() + -- Clear parent references for all children + for _, child in ipairs(self.children) do + child.parent = nil + end + + -- Clear the children table + self.children = {} + + -- Recalculate auto-sizing if needed + if self.autosizing.width or self.autosizing.height then + if self.autosizing.width then + local contentWidth = self:calculateAutoWidth() + self._borderBoxWidth = contentWidth + self.padding.left + self.padding.right + self.width = contentWidth + end + if self.autosizing.height then + local contentHeight = self:calculateAutoHeight() + self._borderBoxHeight = contentHeight + self.padding.top + self.padding.bottom + self.height = contentHeight + end + end + + -- Re-layout (though there are no children now) + if not self._deps.Context._immediateMode then + self:layoutChildren() + end +end + +--- Get the number of children this element has +---@return number +function Element:getChildCount() + return #self.children +end + --- Apply positioning offsets (top, right, bottom, left) to an element -- @param element The element to apply offsets to function Element:applyPositioningOffsets(element) diff --git a/testing/__tests__/element_di_test.lua b/testing/__tests__/element_di_test.lua deleted file mode 100644 index ee33992..0000000 --- a/testing/__tests__/element_di_test.lua +++ /dev/null @@ -1,186 +0,0 @@ --- Test that demonstrates dependency injection with mocked dependencies -package.path = package.path .. ";../../?.lua;../?.lua" -local luaunit = require("testing.luaunit") -local Element = require("modules.Element") - --- Mock dependencies -local function createMockDeps() - return { - Context = { - _immediateMode = false, - defaultTheme = "test", - scaleFactors = { x = 1, y = 1 }, - registerElement = function() end, - topElements = {}, - }, - Theme = { - Manager = { - new = function() - return { - getThemeState = function() return "normal" end, - update = function() end, - } - end - }, - }, - Color = { - new = function(r, g, b, a) - return { r = r or 0, g = g or 0, b = b or 0, a = a or 1 } - end, - }, - Units = { - getViewport = function() return 1920, 1080 end, - parse = function(value) - if type(value) == "number" then - return value, "px" - end - return 100, "px" - end, - }, - Blur = {}, - ImageRenderer = {}, - NinePatch = {}, - RoundedRect = {}, - ImageCache = {}, - utils = { - enums = { - Positioning = { RELATIVE = "relative", ABSOLUTE = "absolute", FLEX = "flex", GRID = "grid" }, - FlexDirection = { HORIZONTAL = "horizontal", VERTICAL = "vertical" }, - JustifyContent = { FLEX_START = "flex-start", FLEX_END = "flex-end", CENTER = "center" }, - AlignContent = { STRETCH = "stretch", FLEX_START = "flex-start", FLEX_END = "flex-end" }, - AlignItems = { STRETCH = "stretch", FLEX_START = "flex-start", FLEX_END = "flex-end", CENTER = "center" }, - TextAlign = { LEFT = "left", CENTER = "center", RIGHT = "right" }, - AlignSelf = { AUTO = "auto", STRETCH = "stretch", FLEX_START = "flex-start" }, - JustifySelf = { AUTO = "auto", FLEX_START = "flex-start", FLEX_END = "flex-end" }, - FlexWrap = { NOWRAP = "nowrap", WRAP = "wrap" }, - }, - validateEnum = function() end, - validateRange = function() end, - validateType = function() end, - resolveTextSizePreset = function(size) return size end, - getModifiers = function() return false, false, false, false end, - }, - Grid = {}, - InputEvent = { - new = function() return {} end, - }, - StateManager = { - generateID = function() return "test-id" end, - }, - TextEditor = { - new = function() - return { - initialize = function() end, - } - end, - }, - LayoutEngine = { - new = function() - return { - initialize = function() end, - calculateLayout = function() end, - } - end, - }, - Renderer = { - new = function() - return { - initialize = function() end, - draw = function() end, - } - end, - }, - EventHandler = { - new = function() - return { - initialize = function() end, - getState = function() return {} end, - } - end, - }, - ScrollManager = { - new = function() - return { - initialize = function() end, - } - end, - }, - ErrorHandler = { - handle = function() end, - }, - } -end - -TestDependencyInjection = {} - -function TestDependencyInjection:test_element_with_mocked_dependencies() - -- Create mock dependencies - local mockDeps = createMockDeps() - - -- Track if Context.registerElement was called - local registerCalled = false - mockDeps.Context.registerElement = function() - registerCalled = true - end - - -- Create element with mocked dependencies - local element = Element.new({ - id = "test-element", - width = 100, - height = 100, - x = 0, - y = 0, - }, mockDeps) - - -- Verify element was created - luaunit.assertNotNil(element) - luaunit.assertEquals(element.id, "test-element") - luaunit.assertEquals(element.width, 100) - luaunit.assertEquals(element.height, 100) - - -- Verify the element is using our mocked dependencies - luaunit.assertEquals(element._deps, mockDeps) - - -- Verify Context.registerElement was called - luaunit.assertTrue(registerCalled) -end - -function TestDependencyInjection:test_element_without_deps_should_error() - -- Element.new now requires deps parameter - local success, err = pcall(function() - Element.new({ - id = "test-element", - width = 100, - height = 100, - }) - end) - - luaunit.assertFalse(success) - luaunit.assertNotNil(err) - luaunit.assertStrContains(err, "deps") -end - -function TestDependencyInjection:test_can_mock_specific_module_behavior() - local mockDeps = createMockDeps() - - -- Mock Units.parse to return specific values - local parseCallCount = 0 - mockDeps.Units.parse = function(value) - parseCallCount = parseCallCount + 1 - return 200, "px" -- Always return 200px - end - - -- Create element (this will call Units.parse) - local element = Element.new({ - id = "test", - width = "50%", -- This should be parsed by our mock - height = 100, - x = 0, - y = 0, - }, mockDeps) - - -- Verify our mock was called - luaunit.assertTrue(parseCallCount > 0, "Units.parse should have been called") -end - -os.exit(luaunit.LuaUnit.run()) diff --git a/testing/__tests__/element_test.lua b/testing/__tests__/element_test.lua index c722f85..0135bc0 100644 --- a/testing/__tests__/element_test.lua +++ b/testing/__tests__/element_test.lua @@ -396,11 +396,6 @@ function TestElementFlex:test_element_with_gap() luaunit.assertEquals(element.gap, 10) end --- Run tests if this file is executed directly -if not _G.RUNNING_ALL_TESTS then - os.exit(luaunit.LuaUnit.run()) -end - -- Test suite for Element styling properties TestElementStyling = {} @@ -532,4 +527,703 @@ function TestElementMethods:test_element_addChild() luaunit.assertEquals(parent.children[1], child) luaunit.assertEquals(child.parent, parent) end +-- Test suite for scroll-related functions +TestElementScroll = {} +function TestElementScroll:setUp() + FlexLove.beginFrame(1920, 1080) +end + +function TestElementScroll:tearDown() + FlexLove.endFrame() +end + +function TestElementScroll:test_scrollable_element_with_overflow() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + luaunit.assertNotNil(element) + luaunit.assertEquals(element.overflow, "scroll") + luaunit.assertNotNil(element._scrollManager) +end + +function TestElementScroll:test_setScrollPosition() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + element:setScrollPosition(50, 100) + local scrollX, scrollY = element:getScrollPosition() + + -- Note: actual scroll may be clamped based on content + luaunit.assertNotNil(scrollX) + luaunit.assertNotNil(scrollY) +end + +function TestElementScroll:test_scrollBy() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + local initialX, initialY = element:getScrollPosition() + element:scrollBy(10, 20) + local newX, newY = element:getScrollPosition() + + luaunit.assertNotNil(newX) + luaunit.assertNotNil(newY) +end + +function TestElementScroll:test_scrollToTop() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + element:scrollToTop() + local _, scrollY = element:getScrollPosition() + luaunit.assertEquals(scrollY, 0) +end + +function TestElementScroll:test_scrollToBottom() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + element:scrollToBottom() + -- Bottom position depends on content, just verify it doesn't error + local _, scrollY = element:getScrollPosition() + luaunit.assertNotNil(scrollY) +end + +function TestElementScroll:test_scrollToLeft() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + element:scrollToLeft() + local scrollX, _ = element:getScrollPosition() + luaunit.assertEquals(scrollX, 0) +end + +function TestElementScroll:test_scrollToRight() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + element:scrollToRight() + local scrollX, _ = element:getScrollPosition() + luaunit.assertNotNil(scrollX) +end + +function TestElementScroll:test_getMaxScroll() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + local maxX, maxY = element:getMaxScroll() + luaunit.assertNotNil(maxX) + luaunit.assertNotNil(maxY) +end + +function TestElementScroll:test_getScrollPercentage() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + local percentX, percentY = element:getScrollPercentage() + luaunit.assertNotNil(percentX) + luaunit.assertNotNil(percentY) + luaunit.assertTrue(percentX >= 0 and percentX <= 1) + luaunit.assertTrue(percentY >= 0 and percentY <= 1) +end + +function TestElementScroll:test_hasOverflow() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + local hasOverflowX, hasOverflowY = element:hasOverflow() + luaunit.assertNotNil(hasOverflowX) + luaunit.assertNotNil(hasOverflowY) +end + +function TestElementScroll:test_getContentSize() + local element = FlexLove.new({ + id = "scrollable", + x = 0, + y = 0, + width = 200, + height = 200, + overflow = "scroll" + }) + + local contentWidth, contentHeight = element:getContentSize() + luaunit.assertNotNil(contentWidth) + luaunit.assertNotNil(contentHeight) +end + +-- Test suite for element geometry and bounds +TestElementGeometry = {} + +function TestElementGeometry:setUp() + FlexLove.beginFrame(1920, 1080) +end + +function TestElementGeometry:tearDown() + FlexLove.endFrame() +end + +function TestElementGeometry:test_getBounds() + local element = FlexLove.new({ + id = "test", + x = 10, + y = 20, + width = 100, + height = 50 + }) + + local bounds = element:getBounds() + luaunit.assertEquals(bounds.x, 10) + luaunit.assertEquals(bounds.y, 20) + luaunit.assertEquals(bounds.width, 100) + luaunit.assertEquals(bounds.height, 50) +end + +function TestElementGeometry:test_contains_point_inside() + local element = FlexLove.new({ + id = "test", + x = 10, + y = 20, + width = 100, + height = 50 + }) + + luaunit.assertTrue(element:contains(50, 40)) +end + +function TestElementGeometry:test_contains_point_outside() + local element = FlexLove.new({ + id = "test", + x = 10, + y = 20, + width = 100, + height = 50 + }) + + luaunit.assertFalse(element:contains(200, 200)) +end + +function TestElementGeometry:test_getBorderBoxWidth_no_border() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 50 + }) + + local borderBoxWidth = element:getBorderBoxWidth() + luaunit.assertEquals(borderBoxWidth, 100) +end + +function TestElementGeometry:test_getBorderBoxHeight_no_border() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 50 + }) + + local borderBoxHeight = element:getBorderBoxHeight() + luaunit.assertEquals(borderBoxHeight, 50) +end + +function TestElementGeometry:test_getBorderBoxWidth_with_border() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 50, + border = { left = 2, right = 2, top = 0, bottom = 0 } + }) + + local borderBoxWidth = element:getBorderBoxWidth() + -- Width includes left + right borders + luaunit.assertTrue(borderBoxWidth >= 100) +end + +function TestElementGeometry:test_getAvailableContentWidth() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 200, + height = 100, + padding = { top = 10, right = 10, bottom = 10, left = 10 } + }) + + local availWidth = element:getAvailableContentWidth() + luaunit.assertNotNil(availWidth) + -- Should be less than total width due to padding + luaunit.assertTrue(availWidth <= 200) +end + +function TestElementGeometry:test_getAvailableContentHeight() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 200, + height = 100, + padding = { top = 10, right = 10, bottom = 10, left = 10 } + }) + + local availHeight = element:getAvailableContentHeight() + luaunit.assertNotNil(availHeight) + -- Should be less than total height due to padding + luaunit.assertTrue(availHeight <= 100) +end + +function TestElementGeometry:test_getScaledContentPadding() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 200, + height = 100, + padding = { top = 10, right = 10, bottom = 10, left = 10 } + }) + + local padding = element:getScaledContentPadding() + -- May be nil if no theme component with contentPadding + if padding then + luaunit.assertNotNil(padding.top) + luaunit.assertNotNil(padding.right) + luaunit.assertNotNil(padding.bottom) + luaunit.assertNotNil(padding.left) + end +end + +-- Test suite for child management +TestElementChildren = {} + +function TestElementChildren:setUp() + FlexLove.beginFrame(1920, 1080) +end + +function TestElementChildren:tearDown() + FlexLove.endFrame() +end + +function TestElementChildren:test_addChild() + local parent = FlexLove.new({ + id = "parent", + x = 0, + y = 0, + width = 200, + height = 200 + }) + + local child = FlexLove.new({ + id = "child", + x = 10, + y = 10, + width = 50, + height = 50 + }) + + parent:addChild(child) + luaunit.assertEquals(#parent.children, 1) + luaunit.assertEquals(parent.children[1], child) + luaunit.assertEquals(child.parent, parent) +end + +function TestElementChildren:test_removeChild() + local parent = FlexLove.new({ + id = "parent", + x = 0, + y = 0, + width = 200, + height = 200 + }) + + local child = FlexLove.new({ + id = "child", + x = 10, + y = 10, + width = 50, + height = 50 + }) + + parent:addChild(child) + parent:removeChild(child) + + luaunit.assertEquals(#parent.children, 0) + luaunit.assertNil(child.parent) +end + +function TestElementChildren:test_clearChildren() + local parent = FlexLove.new({ + id = "parent", + x = 0, + y = 0, + width = 200, + height = 200 + }) + + local child1 = FlexLove.new({ id = "child1", x = 0, y = 0, width = 50, height = 50 }) + local child2 = FlexLove.new({ id = "child2", x = 0, y = 0, width = 50, height = 50 }) + + parent:addChild(child1) + parent:addChild(child2) + parent:clearChildren() + + luaunit.assertEquals(#parent.children, 0) +end + +function TestElementChildren:test_getChildCount() + local parent = FlexLove.new({ + id = "parent", + x = 0, + y = 0, + width = 200, + height = 200 + }) + + local child1 = FlexLove.new({ id = "child1", x = 0, y = 0, width = 50, height = 50 }) + local child2 = FlexLove.new({ id = "child2", x = 0, y = 0, width = 50, height = 50 }) + + parent:addChild(child1) + parent:addChild(child2) + + luaunit.assertEquals(parent:getChildCount(), 2) +end + +-- Test suite for element visibility and opacity +TestElementVisibility = {} + +function TestElementVisibility:setUp() + FlexLove.beginFrame(1920, 1080) +end + +function TestElementVisibility:tearDown() + FlexLove.endFrame() +end + +function TestElementVisibility:test_visibility_visible() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + visibility = "visible" + }) + + luaunit.assertEquals(element.visibility, "visible") +end + +function TestElementVisibility:test_visibility_hidden() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + visibility = "hidden" + }) + + luaunit.assertEquals(element.visibility, "hidden") +end + +function TestElementVisibility:test_opacity_default() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100 + }) + + luaunit.assertEquals(element.opacity, 1) +end + +function TestElementVisibility:test_opacity_custom() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + opacity = 0.5 + }) + + luaunit.assertEquals(element.opacity, 0.5) +end + +-- Test suite for text editing +TestElementTextEditing = {} + +function TestElementTextEditing:setUp() + FlexLove.beginFrame(1920, 1080) +end + +function TestElementTextEditing:tearDown() + FlexLove.endFrame() +end + +function TestElementTextEditing:test_editable_element() + local element = FlexLove.new({ + id = "input", + x = 0, + y = 0, + width = 200, + height = 40, + editable = true, + text = "Edit me" + }) + + luaunit.assertTrue(element.editable) + luaunit.assertNotNil(element._textEditor) +end + +function TestElementTextEditing:test_placeholder_text() + local element = FlexLove.new({ + id = "input", + x = 0, + y = 0, + width = 200, + height = 40, + editable = true, + placeholder = "Enter text..." + }) + + luaunit.assertEquals(element.placeholder, "Enter text...") +end + +-- Test suite for additional element features +TestElementAdditional = {} + +function TestElementAdditional:setUp() + FlexLove.beginFrame(1920, 1080) +end + +function TestElementAdditional:tearDown() + FlexLove.endFrame() +end + +function TestElementAdditional:test_element_with_z_index() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + z = 10 + }) + + luaunit.assertEquals(element.z, 10) +end + +function TestElementAdditional:test_element_with_text() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + text = "Hello World" + }) + + luaunit.assertEquals(element.text, "Hello World") +end + +function TestElementAdditional:test_element_with_text_color() + local Color = require("modules.Color") + local textColor = Color.new(255, 0, 0, 1) + + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + text = "Red text", + textColor = textColor + }) + + luaunit.assertEquals(element.textColor, textColor) +end + +function TestElementAdditional:test_element_with_background_color() + local Color = require("modules.Color") + local bgColor = Color.new(0, 0, 255, 1) + + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + backgroundColor = bgColor + }) + + luaunit.assertEquals(element.backgroundColor, bgColor) +end + +function TestElementAdditional:test_element_with_corner_radius() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + cornerRadius = 10 + }) + + luaunit.assertNotNil(element.cornerRadius) + luaunit.assertEquals(element.cornerRadius.topLeft, 10) + luaunit.assertEquals(element.cornerRadius.topRight, 10) + luaunit.assertEquals(element.cornerRadius.bottomLeft, 10) + luaunit.assertEquals(element.cornerRadius.bottomRight, 10) +end + +function TestElementAdditional:test_element_with_margin() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + margin = { top = 5, right = 10, bottom = 5, left = 10 } + }) + + luaunit.assertNotNil(element.margin) + luaunit.assertEquals(element.margin.top, 5) + luaunit.assertEquals(element.margin.right, 10) + luaunit.assertEquals(element.margin.bottom, 5) + luaunit.assertEquals(element.margin.left, 10) +end + +function TestElementAdditional:test_element_destroy() + local parent = FlexLove.new({ + id = "parent", + x = 0, + y = 0, + width = 200, + height = 200 + }) + + local child = FlexLove.new({ + id = "child", + parent = parent, + x = 0, + y = 0, + width = 50, + height = 50 + }) + + luaunit.assertEquals(#parent.children, 1) + child:destroy() + luaunit.assertNil(child.parent) +end + +function TestElementAdditional:test_element_with_disabled() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + disabled = true + }) + + luaunit.assertTrue(element.disabled) +end + +function TestElementAdditional:test_element_with_active() + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + active = true + }) + + luaunit.assertTrue(element.active) +end + +function TestElementAdditional:test_element_with_userdata() + local customData = { foo = "bar", count = 42 } + + local element = FlexLove.new({ + id = "test", + x = 0, + y = 0, + width = 100, + height = 100, + userdata = customData + }) + + luaunit.assertEquals(element.userdata, customData) + luaunit.assertEquals(element.userdata.foo, "bar") + luaunit.assertEquals(element.userdata.count, 42) +end + + +if not _G.RUNNING_ALL_TESTS then + os.exit(luaunit.LuaUnit.run()) +end diff --git a/testing/__tests__/layout_engine_integration_test.lua b/testing/__tests__/layout_engine_integration_test.lua deleted file mode 100644 index 5b8dee7..0000000 --- a/testing/__tests__/layout_engine_integration_test.lua +++ /dev/null @@ -1,441 +0,0 @@ --- Integration tests for LayoutEngine.lua --- Tests actual layout calculations with mock element structures - -package.path = package.path .. ";./?.lua;./modules/?.lua" - --- Load love stub before anything else -require("testing.loveStub") - -local luaunit = require("testing.luaunit") -local LayoutEngine = require("modules.LayoutEngine") -local Units = require("modules.Units") -local utils = require("modules.utils") - --- Mock dependencies -local mockContext = { - getScaleFactors = function() - return 1, 1 - end, - baseScale = 1, - _cachedViewport = { width = 1920, height = 1080 }, -} - -local mockErrorHandler = { - error = function(module, msg) end, - warn = function(module, msg) end, -} - -local mockGrid = { - layoutGridItems = function(element) end, -} - -local deps = { - utils = utils, - Grid = mockGrid, - Units = Units, - Context = mockContext, - ErrorHandler = mockErrorHandler, -} - --- Helper function to create mock element -local function createMockElement(props) - return { - id = props.id or "mock", - x = props.x or 0, - y = props.y or 0, - width = props.width or 100, - height = props.height or 100, - absoluteX = props.absoluteX or 0, - absoluteY = props.absoluteY or 0, - marginLeft = props.marginLeft or 0, - marginTop = props.marginTop or 0, - marginRight = props.marginRight or 0, - marginBottom = props.marginBottom or 0, - children = props.children or {}, - parent = props.parent, - isHidden = props.isHidden or false, - flexGrow = props.flexGrow or 0, - flexShrink = props.flexShrink or 1, - flexBasis = props.flexBasis or "auto", - alignSelf = props.alignSelf, - minWidth = props.minWidth, - maxWidth = props.maxWidth, - minHeight = props.minHeight, - maxHeight = props.maxHeight, - text = props.text, - _layout = nil, - recalculateUnits = function() end, - layoutChildren = function() end, - } -end - --- Test suite for layoutChildren with flex layout -TestLayoutChildrenFlex = {} - -function TestLayoutChildrenFlex:test_layoutChildren_horizontal_flex_start() - local props = { - positioning = utils.enums.Positioning.FLEX, - flexDirection = utils.enums.FlexDirection.HORIZONTAL, - justifyContent = utils.enums.JustifyContent.FLEX_START, - alignItems = utils.enums.AlignItems.FLEX_START, - gap = 10, - } - local layout = LayoutEngine.new(props, deps) - - local parent = createMockElement({ - id = "parent", - width = 300, - height = 100, - }) - - local child1 = createMockElement({ - id = "child1", - width = 50, - height = 30, - parent = parent, - }) - - local child2 = createMockElement({ - id = "child2", - width = 60, - height = 40, - parent = parent, - }) - - parent.children = { child1, child2 } - parent._layout = layout - - layout:initialize(parent) - layout:layoutChildren() - - -- Verify layout was calculated (children positions should be set) - -- Child1 should be at (0, 0) - luaunit.assertEquals(child1.x, 0) - luaunit.assertEquals(child1.y, 0) - - -- Child2 should be at (50 + gap, 0) = (60, 0) - luaunit.assertEquals(child2.x, 60) - luaunit.assertEquals(child2.y, 0) -end - -function TestLayoutChildrenFlex:test_layoutChildren_vertical_flex_start() - local props = { - positioning = utils.enums.Positioning.FLEX, - flexDirection = utils.enums.FlexDirection.VERTICAL, - justifyContent = utils.enums.JustifyContent.FLEX_START, - alignItems = utils.enums.AlignItems.FLEX_START, - gap = 5, - } - local layout = LayoutEngine.new(props, deps) - - local parent = createMockElement({ - id = "parent", - width = 100, - height = 200, - }) - - local child1 = createMockElement({ - id = "child1", - width = 50, - height = 30, - parent = parent, - }) - - local child2 = createMockElement({ - id = "child2", - width = 60, - height = 40, - parent = parent, - }) - - parent.children = { child1, child2 } - parent._layout = layout - - layout:initialize(parent) - layout:layoutChildren() - - -- Verify layout was calculated - luaunit.assertEquals(child1.x, 0) - luaunit.assertEquals(child1.y, 0) - - -- Child2 should be below child1 with gap - luaunit.assertEquals(child2.x, 0) - luaunit.assertEquals(child2.y, 35) -- 30 + 5 -end - -function TestLayoutChildrenFlex:test_layoutChildren_with_margins() - local props = { - positioning = utils.enums.Positioning.FLEX, - flexDirection = utils.enums.FlexDirection.HORIZONTAL, - justifyContent = utils.enums.JustifyContent.FLEX_START, - gap = 0, - } - local layout = LayoutEngine.new(props, deps) - - local parent = createMockElement({ - id = "parent", - width = 300, - height = 100, - }) - - local child1 = createMockElement({ - id = "child1", - width = 50, - height = 30, - marginLeft = 10, - marginRight = 5, - parent = parent, - }) - - parent.children = { child1 } - parent._layout = layout - - layout:initialize(parent) - layout:layoutChildren() - - -- Child should be offset by left margin - luaunit.assertEquals(child1.x, 10) -end - -function TestLayoutChildrenFlex:test_layoutChildren_with_hidden_children() - local props = { - positioning = utils.enums.Positioning.FLEX, - flexDirection = utils.enums.FlexDirection.HORIZONTAL, - gap = 10, - } - local layout = LayoutEngine.new(props, deps) - - local parent = createMockElement({ - id = "parent", - width = 300, - height = 100, - }) - - local child1 = createMockElement({ - id = "child1", - width = 50, - height = 30, - parent = parent, - }) - - local child2 = createMockElement({ - id = "child2", - width = 60, - height = 40, - isHidden = true, - parent = parent, - }) - - local child3 = createMockElement({ - id = "child3", - width = 70, - height = 35, - parent = parent, - }) - - parent.children = { child1, child2, child3 } - parent._layout = layout - - layout:initialize(parent) - layout:layoutChildren() - - -- Child2 should be skipped, so child3 should be positioned after child1 - luaunit.assertEquals(child1.x, 0) - luaunit.assertEquals(child3.x, 60) -- 50 + gap (10) -end - -function TestLayoutChildrenFlex:test_layoutChildren_center() - local props = { - positioning = utils.enums.Positioning.FLEX, - flexDirection = utils.enums.FlexDirection.HORIZONTAL, - justifyContent = utils.enums.JustifyContent.CENTER, - alignItems = utils.enums.AlignItems.CENTER, - gap = 10, - } - local layout = LayoutEngine.new(props, deps) - - local parent = createMockElement({ - id = "parent", - width = 300, - height = 100, - }) - - local child1 = createMockElement({ - id = "child1", - width = 50, - height = 30, - parent = parent, - }) - - local child2 = createMockElement({ - id = "child2", - width = 60, - height = 40, - parent = parent, - }) - - parent.children = { child1, child2 } - parent._layout = layout - - layout:initialize(parent) - layout:layoutChildren() - - -- Children should be centered - -- Total width needed: 50 + 10 + 60 = 120 - -- Remaining space: 300 - 120 = 180 - -- Center offset: 180 / 2 = 90 - luaunit.assertEquals(child1.x, 90) - luaunit.assertEquals(child2.x, 150) -- 90 + 50 + 10 - - -- Vertical centering - -- Child1 height 30, container 100, offset = (100-30)/2 = 35 - luaunit.assertEquals(child1.y, 35) - -- Child2 height 40, offset = (100-40)/2 = 30 - luaunit.assertEquals(child2.y, 30) -end - -function TestLayoutChildrenFlex:test_layoutChildren_space_between() - local props = { - positioning = utils.enums.Positioning.FLEX, - flexDirection = utils.enums.FlexDirection.HORIZONTAL, - justifyContent = utils.enums.JustifyContent.SPACE_BETWEEN, - gap = 0, - } - local layout = LayoutEngine.new(props, deps) - - local parent = createMockElement({ - id = "parent", - width = 300, - height = 100, - }) - - local child1 = createMockElement({ - id = "child1", - width = 50, - height = 30, - parent = parent, - }) - - local child2 = createMockElement({ - id = "child2", - width = 60, - height = 40, - parent = parent, - }) - - parent.children = { child1, child2 } - parent._layout = layout - - layout:initialize(parent) - layout:layoutChildren() - - -- First child at start - luaunit.assertEquals(child1.x, 0) - - -- Last child at end: 300 - 60 = 240 - luaunit.assertEquals(child2.x, 240) -end - --- Test suite for applyPositioningOffsets -TestApplyPositioningOffsets = {} - -function TestApplyPositioningOffsets:test_applyPositioningOffsets_relative() - local props = { - positioning = utils.enums.Positioning.FLEX, - } - local layout = LayoutEngine.new(props, deps) - - local parent = createMockElement({ - id = "parent", - x = 100, - y = 50, - }) - - local child = createMockElement({ - id = "child", - x = 20, - y = 30, - parent = parent, - }) - - layout:initialize(parent) - layout:applyPositioningOffsets(child) - - -- Relative positioning: child keeps its x, y - luaunit.assertEquals(child.x, 20) - luaunit.assertEquals(child.y, 30) -end - -function TestApplyPositioningOffsets:test_applyPositioningOffsets_absolute() - local props = { - positioning = utils.enums.Positioning.ABSOLUTE, - } - local layout = LayoutEngine.new(props, deps) - - local parent = createMockElement({ - id = "parent", - absoluteX = 100, - absoluteY = 50, - width = 300, - height = 200, - }) - - local child = createMockElement({ - id = "child", - x = 20, - y = 30, - parent = parent, - }) - - layout:initialize(parent) - layout:applyPositioningOffsets(child) - - -- Absolute positioning: child.x, child.y are relative to parent - luaunit.assertEquals(child.absoluteX, 120) -- 100 + 20 - luaunit.assertEquals(child.absoluteY, 80) -- 50 + 30 -end - --- Test suite for grid layout -TestLayoutChildrenGrid = {} - -function TestLayoutChildrenGrid:test_layoutChildren_grid_delegates_to_Grid() - local gridCalled = false - local mockGridForTest = { - layoutGridItems = function(element) - gridCalled = true - end, - } - - local depsWithMockGrid = { - utils = utils, - Grid = mockGridForTest, - Units = Units, - Context = mockContext, - ErrorHandler = mockErrorHandler, - } - - local props = { - positioning = utils.enums.Positioning.GRID, - gridRows = 2, - gridColumns = 2, - } - local layout = LayoutEngine.new(props, depsWithMockGrid) - - local parent = createMockElement({ - id = "parent", - width = 300, - height = 200, - }) - - parent._layout = layout - layout:initialize(parent) - layout:layoutChildren() - - -- Verify Grid.layoutGridItems was called - luaunit.assertTrue(gridCalled) -end - --- Run tests if this file is executed directly -if not _G.RUNNING_ALL_TESTS then - os.exit(luaunit.LuaUnit.run()) -end diff --git a/testing/__tests__/layout_engine_test.lua b/testing/__tests__/layout_engine_test.lua index bc9632e..72eec65 100644 --- a/testing/__tests__/layout_engine_test.lua +++ b/testing/__tests__/layout_engine_test.lua @@ -655,7 +655,69 @@ function TestLayoutEngineEdgeCases:testAutoWidthWithTextAndChildren() luaunit.assertEquals(width, 150) end --- Run tests if not running as part of a suite +local Units = require("modules.Units") +local utils = require("modules.utils") + +-- Mock dependencies +local mockContext = { + getScaleFactors = function() + return 1, 1 + end, + baseScale = 1, + _cachedViewport = { width = 1920, height = 1080 }, +} + +local mockErrorHandler = { + error = function(module, msg) end, + warn = function(module, msg) end, +} + +local mockGrid = { + layoutGridItems = function(element) end, +} + +local deps = { + utils = utils, + Grid = mockGrid, + Units = Units, + Context = mockContext, + ErrorHandler = mockErrorHandler, +} + +-- Helper function to create mock element +local function createMockElement(props) + return { + id = props.id or "mock", + x = props.x or 0, + y = props.y or 0, + width = props.width or 100, + height = props.height or 100, + absoluteX = props.absoluteX or 0, + absoluteY = props.absoluteY or 0, + marginLeft = props.marginLeft or 0, + marginTop = props.marginTop or 0, + marginRight = props.marginRight or 0, + marginBottom = props.marginBottom or 0, + children = props.children or {}, + parent = props.parent, + isHidden = props.isHidden or false, + flexGrow = props.flexGrow or 0, + flexShrink = props.flexShrink or 1, + flexBasis = props.flexBasis or "auto", + alignSelf = props.alignSelf, + minWidth = props.minWidth, + maxWidth = props.maxWidth, + minHeight = props.minHeight, + maxHeight = props.maxHeight, + text = props.text, + _layout = nil, + recalculateUnits = function() end, + layoutChildren = function() end, + } +end + + +-- Run tests if this file is executed directly if not _G.RUNNING_ALL_TESTS then os.exit(luaunit.LuaUnit.run()) end diff --git a/testing/__tests__/sanitization_test.lua b/testing/__tests__/sanitization_test.lua index b72b037..bb751a9 100644 --- a/testing/__tests__/sanitization_test.lua +++ b/testing/__tests__/sanitization_test.lua @@ -230,6 +230,299 @@ function TestStripNonPrintable:testStripNonPrintable_EmptyString() luaunit.assertEquals(result, "") end +-- Mock dependencies +local mockContext = { + _immediateMode = false, + _focusedElement = nil, +} + +local mockStateManager = { + getState = function() + return nil + end, + setState = function() end, +} + +-- Test Suite for TextEditor Sanitization +TestTextEditorSanitization = {} + +---Helper to create a TextEditor instance +function TestTextEditorSanitization:_createEditor(config) + local TextEditor = require("modules.TextEditor") + config = config or {} + local deps = { + Context = mockContext, + StateManager = mockStateManager, + Color = Color, + utils = utils, + } + return TextEditor.new(config, deps) +end + +-- === Sanitization Enabled Tests === + +function TestTextEditorSanitization:test_sanitization_enabled_by_default() + local editor = self:_createEditor({ editable = true }) + luaunit.assertTrue(editor.sanitize) +end + +function TestTextEditorSanitization:test_sanitization_can_be_disabled() + local editor = self:_createEditor({ editable = true, sanitize = false }) + luaunit.assertFalse(editor.sanitize) +end + +function TestTextEditorSanitization:test_setText_removes_control_characters() + local editor = self:_createEditor({ editable = true }) + editor:setText("Hello\x00World\x01Test") + luaunit.assertEquals(editor:getText(), "HelloWorldTest") +end + +function TestTextEditorSanitization:test_setText_preserves_valid_text() + local editor = self:_createEditor({ editable = true }) + editor:setText("Hello World! 123") + luaunit.assertEquals(editor:getText(), "Hello World! 123") +end + +function TestTextEditorSanitization:test_setText_removes_multiple_control_chars() + local editor = self:_createEditor({ editable = true }) + editor:setText("Test\x00\x01\x02\x03\x04Data") + luaunit.assertEquals(editor:getText(), "TestData") +end + +function TestTextEditorSanitization:test_setText_with_sanitization_disabled() + local editor = self:_createEditor({ editable = true, sanitize = false }) + editor:setText("Hello\x00World") + luaunit.assertEquals(editor:getText(), "Hello\x00World") +end + +function TestTextEditorSanitization:test_setText_skip_sanitization_parameter() + local editor = self:_createEditor({ editable = true }) + editor:setText("Hello\x00World", true) -- skipSanitization = true + luaunit.assertEquals(editor:getText(), "Hello\x00World") +end + +-- === Initial Text Sanitization === + +function TestTextEditorSanitization:test_initial_text_is_sanitized() + local editor = self:_createEditor({ + editable = true, + text = "Initial\x00Text\x01", + }) + luaunit.assertEquals(editor:getText(), "InitialText") +end + +function TestTextEditorSanitization:test_initial_text_preserved_when_disabled() + local editor = self:_createEditor({ + editable = true, + sanitize = false, + text = "Initial\x00Text", + }) + luaunit.assertEquals(editor:getText(), "Initial\x00Text") +end + +-- === insertText Sanitization === + +function TestTextEditorSanitization:test_insertText_sanitizes_input() + local editor = self:_createEditor({ editable = true, text = "Hello" }) + editor:insertText("\x00World", 5) + luaunit.assertEquals(editor:getText(), "HelloWorld") +end + +function TestTextEditorSanitization:test_insertText_with_valid_text() + local editor = self:_createEditor({ editable = true, text = "Hello" }) + editor:insertText(" World", 5) + luaunit.assertEquals(editor:getText(), "Hello World") +end + +function TestTextEditorSanitization:test_insertText_empty_after_sanitization() + local editor = self:_createEditor({ editable = true, text = "Hello" }) + editor:insertText("\x00\x01\x02", 5) -- Only control chars + luaunit.assertEquals(editor:getText(), "Hello") -- Should remain unchanged +end + +-- === Length Limiting === + +function TestTextEditorSanitization:test_maxLength_enforced_on_setText() + local editor = self:_createEditor({ editable = true, maxLength = 10 }) + editor:setText("This is a very long text") + luaunit.assertEquals(#editor:getText(), 10) +end + +function TestTextEditorSanitization:test_maxLength_enforced_on_insertText() + local editor = self:_createEditor({ editable = true, text = "12345", maxLength = 10 }) + editor:insertText("67890", 5) -- This would make it exactly 10 + luaunit.assertEquals(editor:getText(), "1234567890") +end + +function TestTextEditorSanitization:test_maxLength_truncates_excess() + local editor = self:_createEditor({ editable = true, text = "12345", maxLength = 10 }) + editor:insertText("67890EXTRA", 5) -- Would exceed limit + luaunit.assertEquals(editor:getText(), "1234567890") +end + +function TestTextEditorSanitization:test_maxLength_prevents_insert_when_full() + local editor = self:_createEditor({ editable = true, text = "1234567890", maxLength = 10 }) + editor:insertText("X", 10) + luaunit.assertEquals(editor:getText(), "1234567890") -- Should not change +end + +-- === Newline Handling === + +function TestTextEditorSanitization:test_newlines_allowed_in_multiline() + local editor = self:_createEditor({ editable = true, multiline = true }) + editor:setText("Line1\nLine2") + luaunit.assertEquals(editor:getText(), "Line1\nLine2") +end + +function TestTextEditorSanitization:test_newlines_removed_in_singleline() + local editor = self:_createEditor({ editable = true, multiline = false }) + editor:setText("Line1\nLine2") + luaunit.assertEquals(editor:getText(), "Line1Line2") +end + +function TestTextEditorSanitization:test_allowNewlines_explicit_false() + local editor = self:_createEditor({ + editable = true, + multiline = true, + allowNewlines = false, + }) + editor:setText("Line1\nLine2") + luaunit.assertEquals(editor:getText(), "Line1Line2") +end + +-- === Tab Handling === + +function TestTextEditorSanitization:test_tabs_allowed_by_default() + local editor = self:_createEditor({ editable = true }) + editor:setText("Hello\tWorld") + luaunit.assertEquals(editor:getText(), "Hello\tWorld") +end + +function TestTextEditorSanitization:test_tabs_removed_when_disabled() + local editor = self:_createEditor({ + editable = true, + allowTabs = false, + }) + editor:setText("Hello\tWorld") + luaunit.assertEquals(editor:getText(), "HelloWorld") +end + +-- === Custom Sanitizer === + +function TestTextEditorSanitization:test_custom_sanitizer_used() + local customSanitizer = function(text) + return text:upper() + end + + local editor = self:_createEditor({ + editable = true, + customSanitizer = customSanitizer, + }) + editor:setText("hello world") + luaunit.assertEquals(editor:getText(), "HELLO WORLD") +end + +function TestTextEditorSanitization:test_custom_sanitizer_with_control_chars() + local customSanitizer = function(text) + -- Custom sanitizer that replaces control chars with * + return text:gsub("[\x00-\x1F]", "*") + end + + local editor = self:_createEditor({ + editable = true, + customSanitizer = customSanitizer, + }) + editor:setText("Hello\x00World\x01") + luaunit.assertEquals(editor:getText(), "Hello*World*") +end + +-- === Unicode and Special Characters === + +function TestTextEditorSanitization:test_unicode_preserved() + local editor = self:_createEditor({ editable = true }) + editor:setText("Hello δΈ–η•Œ 🌍") + luaunit.assertEquals(editor:getText(), "Hello δΈ–η•Œ 🌍") +end + +function TestTextEditorSanitization:test_emoji_preserved() + local editor = self:_createEditor({ editable = true }) + editor:setText("πŸ˜€πŸ˜ƒπŸ˜„πŸ˜") + luaunit.assertEquals(editor:getText(), "πŸ˜€πŸ˜ƒπŸ˜„πŸ˜") +end + +function TestTextEditorSanitization:test_special_chars_preserved() + local editor = self:_createEditor({ editable = true }) + editor:setText("!@#$%^&*()_+-=[]{}|;':\",./<>?") + luaunit.assertEquals(editor:getText(), "!@#$%^&*()_+-=[]{}|;':\",./<>?") +end + +-- === Edge Cases === + +function TestTextEditorSanitization:test_empty_string() + local editor = self:_createEditor({ editable = true }) + editor:setText("") + luaunit.assertEquals(editor:getText(), "") +end + +function TestTextEditorSanitization:test_only_control_characters() + local editor = self:_createEditor({ editable = true }) + editor:setText("\x00\x01\x02\x03") + luaunit.assertEquals(editor:getText(), "") +end + +function TestTextEditorSanitization:test_nil_text() + local editor = self:_createEditor({ editable = true }) + editor:setText(nil) + luaunit.assertEquals(editor:getText(), "") +end + +function TestTextEditorSanitization:test_very_long_text_with_control_chars() + local editor = self:_createEditor({ editable = true }) + local longText = string.rep("Hello\x00World", 100) + editor:setText(longText) + luaunit.assertStrContains(editor:getText(), "Hello") + luaunit.assertStrContains(editor:getText(), "World") + luaunit.assertNotStrContains(editor:getText(), "\x00") +end + +function TestTextEditorSanitization:test_mixed_valid_and_invalid() + local editor = self:_createEditor({ editable = true }) + editor:setText("Valid\x00Text\x01With\x02Control\x03Chars") + luaunit.assertEquals(editor:getText(), "ValidTextWithControlChars") +end + +-- === Whitespace Handling === + +function TestTextEditorSanitization:test_spaces_preserved() + local editor = self:_createEditor({ editable = true }) + editor:setText("Hello World") + luaunit.assertEquals(editor:getText(), "Hello World") +end + +function TestTextEditorSanitization:test_leading_trailing_spaces_preserved() + local editor = self:_createEditor({ editable = true }) + editor:setText(" Hello World ") + luaunit.assertEquals(editor:getText(), " Hello World ") +end + +-- === Integration Tests === + +function TestTextEditorSanitization:test_cursor_position_after_sanitization() + local editor = self:_createEditor({ editable = true }) + editor:setText("Hello") + editor:insertText("\x00World", 5) + -- Cursor should be at end of "HelloWorld" = position 10 + luaunit.assertEquals(editor._cursorPosition, 10) +end + +function TestTextEditorSanitization:test_multiple_operations() + local editor = self:_createEditor({ editable = true }) + editor:setText("Hello") + editor:insertText(" ", 5) + editor:insertText("World\x00", 6) + luaunit.assertEquals(editor:getText(), "Hello World") +end + -- Run tests if this file is executed directly if not _G.RUNNING_ALL_TESTS then os.exit(luaunit.LuaUnit.run()) diff --git a/testing/__tests__/texteditor_sanitization_test.lua b/testing/__tests__/texteditor_sanitization_test.lua deleted file mode 100644 index 21dafca..0000000 --- a/testing/__tests__/texteditor_sanitization_test.lua +++ /dev/null @@ -1,308 +0,0 @@ --- Import test framework -package.path = package.path .. ";./?.lua;./game/?.lua" -local luaunit = require("testing.luaunit") - --- Set up LΓ–VE stub environment -require("testing.loveStub") - --- Import the TextEditor module and dependencies -local utils = require("modules.utils") -local Color = require("modules.Color") - --- Mock dependencies -local mockContext = { - _immediateMode = false, - _focusedElement = nil, -} - -local mockStateManager = { - getState = function() - return nil - end, - setState = function() end, -} - --- Test Suite for TextEditor Sanitization -TestTextEditorSanitization = {} - ----Helper to create a TextEditor instance -function TestTextEditorSanitization:_createEditor(config) - local TextEditor = require("modules.TextEditor") - config = config or {} - local deps = { - Context = mockContext, - StateManager = mockStateManager, - Color = Color, - utils = utils, - } - return TextEditor.new(config, deps) -end - --- === Sanitization Enabled Tests === - -function TestTextEditorSanitization:test_sanitization_enabled_by_default() - local editor = self:_createEditor({ editable = true }) - luaunit.assertTrue(editor.sanitize) -end - -function TestTextEditorSanitization:test_sanitization_can_be_disabled() - local editor = self:_createEditor({ editable = true, sanitize = false }) - luaunit.assertFalse(editor.sanitize) -end - -function TestTextEditorSanitization:test_setText_removes_control_characters() - local editor = self:_createEditor({ editable = true }) - editor:setText("Hello\x00World\x01Test") - luaunit.assertEquals(editor:getText(), "HelloWorldTest") -end - -function TestTextEditorSanitization:test_setText_preserves_valid_text() - local editor = self:_createEditor({ editable = true }) - editor:setText("Hello World! 123") - luaunit.assertEquals(editor:getText(), "Hello World! 123") -end - -function TestTextEditorSanitization:test_setText_removes_multiple_control_chars() - local editor = self:_createEditor({ editable = true }) - editor:setText("Test\x00\x01\x02\x03\x04Data") - luaunit.assertEquals(editor:getText(), "TestData") -end - -function TestTextEditorSanitization:test_setText_with_sanitization_disabled() - local editor = self:_createEditor({ editable = true, sanitize = false }) - editor:setText("Hello\x00World") - luaunit.assertEquals(editor:getText(), "Hello\x00World") -end - -function TestTextEditorSanitization:test_setText_skip_sanitization_parameter() - local editor = self:_createEditor({ editable = true }) - editor:setText("Hello\x00World", true) -- skipSanitization = true - luaunit.assertEquals(editor:getText(), "Hello\x00World") -end - --- === Initial Text Sanitization === - -function TestTextEditorSanitization:test_initial_text_is_sanitized() - local editor = self:_createEditor({ - editable = true, - text = "Initial\x00Text\x01", - }) - luaunit.assertEquals(editor:getText(), "InitialText") -end - -function TestTextEditorSanitization:test_initial_text_preserved_when_disabled() - local editor = self:_createEditor({ - editable = true, - sanitize = false, - text = "Initial\x00Text", - }) - luaunit.assertEquals(editor:getText(), "Initial\x00Text") -end - --- === insertText Sanitization === - -function TestTextEditorSanitization:test_insertText_sanitizes_input() - local editor = self:_createEditor({ editable = true, text = "Hello" }) - editor:insertText("\x00World", 5) - luaunit.assertEquals(editor:getText(), "HelloWorld") -end - -function TestTextEditorSanitization:test_insertText_with_valid_text() - local editor = self:_createEditor({ editable = true, text = "Hello" }) - editor:insertText(" World", 5) - luaunit.assertEquals(editor:getText(), "Hello World") -end - -function TestTextEditorSanitization:test_insertText_empty_after_sanitization() - local editor = self:_createEditor({ editable = true, text = "Hello" }) - editor:insertText("\x00\x01\x02", 5) -- Only control chars - luaunit.assertEquals(editor:getText(), "Hello") -- Should remain unchanged -end - --- === Length Limiting === - -function TestTextEditorSanitization:test_maxLength_enforced_on_setText() - local editor = self:_createEditor({ editable = true, maxLength = 10 }) - editor:setText("This is a very long text") - luaunit.assertEquals(#editor:getText(), 10) -end - -function TestTextEditorSanitization:test_maxLength_enforced_on_insertText() - local editor = self:_createEditor({ editable = true, text = "12345", maxLength = 10 }) - editor:insertText("67890", 5) -- This would make it exactly 10 - luaunit.assertEquals(editor:getText(), "1234567890") -end - -function TestTextEditorSanitization:test_maxLength_truncates_excess() - local editor = self:_createEditor({ editable = true, text = "12345", maxLength = 10 }) - editor:insertText("67890EXTRA", 5) -- Would exceed limit - luaunit.assertEquals(editor:getText(), "1234567890") -end - -function TestTextEditorSanitization:test_maxLength_prevents_insert_when_full() - local editor = self:_createEditor({ editable = true, text = "1234567890", maxLength = 10 }) - editor:insertText("X", 10) - luaunit.assertEquals(editor:getText(), "1234567890") -- Should not change -end - --- === Newline Handling === - -function TestTextEditorSanitization:test_newlines_allowed_in_multiline() - local editor = self:_createEditor({ editable = true, multiline = true }) - editor:setText("Line1\nLine2") - luaunit.assertEquals(editor:getText(), "Line1\nLine2") -end - -function TestTextEditorSanitization:test_newlines_removed_in_singleline() - local editor = self:_createEditor({ editable = true, multiline = false }) - editor:setText("Line1\nLine2") - luaunit.assertEquals(editor:getText(), "Line1Line2") -end - -function TestTextEditorSanitization:test_allowNewlines_explicit_false() - local editor = self:_createEditor({ - editable = true, - multiline = true, - allowNewlines = false, - }) - editor:setText("Line1\nLine2") - luaunit.assertEquals(editor:getText(), "Line1Line2") -end - --- === Tab Handling === - -function TestTextEditorSanitization:test_tabs_allowed_by_default() - local editor = self:_createEditor({ editable = true }) - editor:setText("Hello\tWorld") - luaunit.assertEquals(editor:getText(), "Hello\tWorld") -end - -function TestTextEditorSanitization:test_tabs_removed_when_disabled() - local editor = self:_createEditor({ - editable = true, - allowTabs = false, - }) - editor:setText("Hello\tWorld") - luaunit.assertEquals(editor:getText(), "HelloWorld") -end - --- === Custom Sanitizer === - -function TestTextEditorSanitization:test_custom_sanitizer_used() - local customSanitizer = function(text) - return text:upper() - end - - local editor = self:_createEditor({ - editable = true, - customSanitizer = customSanitizer, - }) - editor:setText("hello world") - luaunit.assertEquals(editor:getText(), "HELLO WORLD") -end - -function TestTextEditorSanitization:test_custom_sanitizer_with_control_chars() - local customSanitizer = function(text) - -- Custom sanitizer that replaces control chars with * - return text:gsub("[\x00-\x1F]", "*") - end - - local editor = self:_createEditor({ - editable = true, - customSanitizer = customSanitizer, - }) - editor:setText("Hello\x00World\x01") - luaunit.assertEquals(editor:getText(), "Hello*World*") -end - --- === Unicode and Special Characters === - -function TestTextEditorSanitization:test_unicode_preserved() - local editor = self:_createEditor({ editable = true }) - editor:setText("Hello δΈ–η•Œ 🌍") - luaunit.assertEquals(editor:getText(), "Hello δΈ–η•Œ 🌍") -end - -function TestTextEditorSanitization:test_emoji_preserved() - local editor = self:_createEditor({ editable = true }) - editor:setText("πŸ˜€πŸ˜ƒπŸ˜„πŸ˜") - luaunit.assertEquals(editor:getText(), "πŸ˜€πŸ˜ƒπŸ˜„πŸ˜") -end - -function TestTextEditorSanitization:test_special_chars_preserved() - local editor = self:_createEditor({ editable = true }) - editor:setText("!@#$%^&*()_+-=[]{}|;':\",./<>?") - luaunit.assertEquals(editor:getText(), "!@#$%^&*()_+-=[]{}|;':\",./<>?") -end - --- === Edge Cases === - -function TestTextEditorSanitization:test_empty_string() - local editor = self:_createEditor({ editable = true }) - editor:setText("") - luaunit.assertEquals(editor:getText(), "") -end - -function TestTextEditorSanitization:test_only_control_characters() - local editor = self:_createEditor({ editable = true }) - editor:setText("\x00\x01\x02\x03") - luaunit.assertEquals(editor:getText(), "") -end - -function TestTextEditorSanitization:test_nil_text() - local editor = self:_createEditor({ editable = true }) - editor:setText(nil) - luaunit.assertEquals(editor:getText(), "") -end - -function TestTextEditorSanitization:test_very_long_text_with_control_chars() - local editor = self:_createEditor({ editable = true }) - local longText = string.rep("Hello\x00World", 100) - editor:setText(longText) - luaunit.assertStrContains(editor:getText(), "Hello") - luaunit.assertStrContains(editor:getText(), "World") - luaunit.assertNotStrContains(editor:getText(), "\x00") -end - -function TestTextEditorSanitization:test_mixed_valid_and_invalid() - local editor = self:_createEditor({ editable = true }) - editor:setText("Valid\x00Text\x01With\x02Control\x03Chars") - luaunit.assertEquals(editor:getText(), "ValidTextWithControlChars") -end - --- === Whitespace Handling === - -function TestTextEditorSanitization:test_spaces_preserved() - local editor = self:_createEditor({ editable = true }) - editor:setText("Hello World") - luaunit.assertEquals(editor:getText(), "Hello World") -end - -function TestTextEditorSanitization:test_leading_trailing_spaces_preserved() - local editor = self:_createEditor({ editable = true }) - editor:setText(" Hello World ") - luaunit.assertEquals(editor:getText(), " Hello World ") -end - --- === Integration Tests === - -function TestTextEditorSanitization:test_cursor_position_after_sanitization() - local editor = self:_createEditor({ editable = true }) - editor:setText("Hello") - editor:insertText("\x00World", 5) - -- Cursor should be at end of "HelloWorld" = position 10 - luaunit.assertEquals(editor._cursorPosition, 10) -end - -function TestTextEditorSanitization:test_multiple_operations() - local editor = self:_createEditor({ editable = true }) - editor:setText("Hello") - editor:insertText(" ", 5) - editor:insertText("World\x00", 6) - luaunit.assertEquals(editor:getText(), "Hello World") -end - --- Run tests if this file is executed directly -if not _G.RUNNING_ALL_TESTS then - os.exit(luaunit.LuaUnit.run()) -end diff --git a/testing/__tests__/theme_core_test.lua b/testing/__tests__/theme_core_test.lua deleted file mode 100644 index 09ef006..0000000 --- a/testing/__tests__/theme_core_test.lua +++ /dev/null @@ -1,302 +0,0 @@ --- Test suite for Theme.lua core functionality --- Tests theme creation, registration, and retrieval functions - -package.path = package.path .. ";./?.lua;./modules/?.lua" - --- Load love stub before anything else -require("testing.loveStub") - -local luaunit = require("testing.luaunit") -local Theme = require("modules.Theme") -local Color = require("modules.Color") - --- Test suite for Theme.new() -TestThemeNew = {} - -function TestThemeNew:setUp() - -- Clear any registered themes before each test - -- Note: We can't access the themes table directly, but we can work around it -end - -function TestThemeNew:test_new_minimal_theme() - local def = { - name = "Minimal Theme", - } - local theme = Theme.new(def) - luaunit.assertNotNil(theme) - luaunit.assertEquals(theme.name, "Minimal Theme") -end - -function TestThemeNew:test_new_theme_with_components() - local def = { - name = "Test Theme", - components = { - button = { - atlas = "path/to/button.png", - }, - }, - } - local theme = Theme.new(def) - luaunit.assertNotNil(theme) - luaunit.assertEquals(theme.name, "Test Theme") - luaunit.assertNotNil(theme.components.button) -end - -function TestThemeNew:test_new_theme_with_colors() - local def = { - name = "Colored Theme", - colors = { - primary = Color.new(1, 0, 0, 1), - secondary = Color.new(0, 1, 0, 1), - }, - } - local theme = Theme.new(def) - luaunit.assertNotNil(theme) - luaunit.assertNotNil(theme.colors.primary) - luaunit.assertNotNil(theme.colors.secondary) -end - -function TestThemeNew:test_new_theme_with_fonts() - local def = { - name = "Font Theme", - fonts = { - default = "path/to/font.ttf", - }, - } - local theme = Theme.new(def) - luaunit.assertNotNil(theme) - luaunit.assertNotNil(theme.fonts.default) - luaunit.assertEquals(theme.fonts.default, "path/to/font.ttf") -end - -function TestThemeNew:test_new_theme_with_multiplier() - local def = { - name = "Multiplier Theme", - contentAutoSizingMultiplier = { - width = 1.5, - height = 2.0, - }, - } - local theme = Theme.new(def) - luaunit.assertNotNil(theme) - luaunit.assertNotNil(theme.contentAutoSizingMultiplier) - luaunit.assertEquals(theme.contentAutoSizingMultiplier.width, 1.5) - luaunit.assertEquals(theme.contentAutoSizingMultiplier.height, 2.0) -end - -function TestThemeNew:test_new_theme_without_name_fails() - local def = {} - luaunit.assertErrorMsgContains("name", function() - Theme.new(def) - end) -end - -function TestThemeNew:test_new_theme_with_nil_fails() - luaunit.assertErrorMsgContains("nil", function() - Theme.new(nil) - end) -end - -function TestThemeNew:test_new_theme_with_non_table_fails() - luaunit.assertErrorMsgContains("table", function() - Theme.new("not a table") - end) -end - --- Test suite for Theme registration and retrieval -TestThemeRegistration = {} - -function TestThemeRegistration:test_setActive_with_theme_object() - local def = { - name = "Active Theme", - } - local theme = Theme.new(def) - Theme.setActive(theme) - - local active = Theme.getActive() - luaunit.assertNotNil(active) - luaunit.assertEquals(active.name, "Active Theme") -end - -function TestThemeRegistration:test_getActive_returns_nil_initially() - -- This test assumes no theme is active, but other tests may have set one - -- So we'll just check that getActive returns something or nil - local active = Theme.getActive() - -- Just verify it doesn't error - luaunit.assertTrue(active == nil or type(active) == "table") -end - -function TestThemeRegistration:test_hasActive_returns_boolean() - local hasActive = Theme.hasActive() - luaunit.assertTrue(type(hasActive) == "boolean") -end - -function TestThemeRegistration:test_get_returns_nil_for_unregistered_theme() - -- Theme.get() looks up themes in the registered themes table - -- Themes created with Theme.new() and setActive() are not automatically registered - local def = { - name = "Unregistered Theme", - } - local theme = Theme.new(def) - Theme.setActive(theme) - - -- This should return nil because the theme was not loaded from a file - local retrieved = Theme.get("Unregistered Theme") - luaunit.assertNil(retrieved) -end - -function TestThemeRegistration:test_get_returns_nil_for_nonexistent() - local retrieved = Theme.get("Nonexistent Theme 12345") - luaunit.assertNil(retrieved) -end - -function TestThemeRegistration:test_getRegisteredThemes_returns_table() - local themes = Theme.getRegisteredThemes() - luaunit.assertNotNil(themes) - luaunit.assertEquals(type(themes), "table") -end - --- Test suite for Theme.getComponent() -TestThemeComponent = {} - -function TestThemeComponent:setUp() - -- Create and set an active theme with components - local def = { - name = "Component Test Theme", - components = { - button = { - atlas = "path/to/button.png", - }, - panel = { - atlas = "path/to/panel.png", - }, - }, - } - self.theme = Theme.new(def) - Theme.setActive(self.theme) -end - -function TestThemeComponent:test_getComponent_returns_component() - local component = Theme.getComponent("button") - luaunit.assertNotNil(component) - luaunit.assertEquals(component.atlas, "path/to/button.png") -end - -function TestThemeComponent:test_getComponent_returns_nil_for_nonexistent() - local component = Theme.getComponent("nonexistent") - luaunit.assertNil(component) -end - -function TestThemeComponent:test_getComponent_with_state() - -- Add a component with states - local def = { - name = "State Test Theme", - components = { - button = { - atlas = "path/to/button.png", - states = { - hover = { - atlas = "path/to/button_hover.png", - }, - }, - }, - }, - } - local theme = Theme.new(def) - Theme.setActive(theme) - - local component = Theme.getComponent("button", "hover") - luaunit.assertNotNil(component) - luaunit.assertEquals(component.atlas, "path/to/button_hover.png") -end - --- Test suite for Theme.getColor() -TestThemeColor = {} - -function TestThemeColor:setUp() - local def = { - name = "Color Test Theme", - colors = { - primary = Color.new(1, 0, 0, 1), - secondary = Color.new(0, 1, 0, 1), - textColor = Color.new(0.5, 0.5, 0.5, 1), - }, - } - self.theme = Theme.new(def) - Theme.setActive(self.theme) -end - -function TestThemeColor:test_getColor_returns_color() - local color = Theme.getColor("primary") - luaunit.assertNotNil(color) - luaunit.assertEquals(color.r, 1) - luaunit.assertEquals(color.g, 0) - luaunit.assertEquals(color.b, 0) -end - -function TestThemeColor:test_getColor_returns_nil_for_nonexistent() - local color = Theme.getColor("nonexistent") - luaunit.assertNil(color) -end - -function TestThemeColor:test_getColorNames_returns_table() - local names = Theme.getColorNames() - luaunit.assertNotNil(names) - luaunit.assertEquals(type(names), "table") - -- Should contain our defined colors - luaunit.assertTrue(#names >= 3) -end - -function TestThemeColor:test_getAllColors_returns_table() - local colors = Theme.getAllColors() - luaunit.assertNotNil(colors) - luaunit.assertEquals(type(colors), "table") - luaunit.assertNotNil(colors.primary) - luaunit.assertNotNil(colors.secondary) -end - -function TestThemeColor:test_getColorOrDefault_returns_color() - local color = Theme.getColorOrDefault("primary", Color.new(0, 0, 0, 1)) - luaunit.assertNotNil(color) - luaunit.assertEquals(color.r, 1) -end - -function TestThemeColor:test_getColorOrDefault_returns_fallback() - local fallback = Color.new(0.1, 0.2, 0.3, 1) - local color = Theme.getColorOrDefault("nonexistent", fallback) - luaunit.assertNotNil(color) - luaunit.assertEquals(color.r, 0.1) - luaunit.assertEquals(color.g, 0.2) - luaunit.assertEquals(color.b, 0.3) -end - --- Test suite for Theme.getFont() -TestThemeFont = {} - -function TestThemeFont:setUp() - local def = { - name = "Font Test Theme", - fonts = { - default = "path/to/default.ttf", - heading = "path/to/heading.ttf", - }, - } - self.theme = Theme.new(def) - Theme.setActive(self.theme) -end - -function TestThemeFont:test_getFont_returns_font_path() - local font = Theme.getFont("default") - luaunit.assertNotNil(font) - luaunit.assertEquals(font, "path/to/default.ttf") -end - -function TestThemeFont:test_getFont_returns_nil_for_nonexistent() - local font = Theme.getFont("nonexistent") - luaunit.assertNil(font) -end - --- Run tests if this file is executed directly -if not _G.RUNNING_ALL_TESTS then - os.exit(luaunit.LuaUnit.run()) -end diff --git a/testing/__tests__/theme_validation_test.lua b/testing/__tests__/theme_test.lua similarity index 65% rename from testing/__tests__/theme_validation_test.lua rename to testing/__tests__/theme_test.lua index 9e08f55..acbb566 100644 --- a/testing/__tests__/theme_validation_test.lua +++ b/testing/__tests__/theme_test.lua @@ -1,14 +1,301 @@ --- Import test framework -package.path = package.path .. ";./?.lua;./game/?.lua" -local luaunit = require("testing.luaunit") +-- Test suite for Theme.lua core functionality +-- Tests theme creation, registration, and retrieval functions --- Set up LΓ–VE stub environment +package.path = package.path .. ";./?.lua;./modules/?.lua" + +-- Load love stub before anything else require("testing.loveStub") --- Import the Theme module +local luaunit = require("testing.luaunit") local Theme = require("modules.Theme") local Color = require("modules.Color") +-- Test suite for Theme.new() +TestThemeNew = {} + +function TestThemeNew:setUp() + -- Clear any registered themes before each test + -- Note: We can't access the themes table directly, but we can work around it +end + +function TestThemeNew:test_new_minimal_theme() + local def = { + name = "Minimal Theme", + } + local theme = Theme.new(def) + luaunit.assertNotNil(theme) + luaunit.assertEquals(theme.name, "Minimal Theme") +end + +function TestThemeNew:test_new_theme_with_components() + local def = { + name = "Test Theme", + components = { + button = { + atlas = "path/to/button.png", + }, + }, + } + local theme = Theme.new(def) + luaunit.assertNotNil(theme) + luaunit.assertEquals(theme.name, "Test Theme") + luaunit.assertNotNil(theme.components.button) +end + +function TestThemeNew:test_new_theme_with_colors() + local def = { + name = "Colored Theme", + colors = { + primary = Color.new(1, 0, 0, 1), + secondary = Color.new(0, 1, 0, 1), + }, + } + local theme = Theme.new(def) + luaunit.assertNotNil(theme) + luaunit.assertNotNil(theme.colors.primary) + luaunit.assertNotNil(theme.colors.secondary) +end + +function TestThemeNew:test_new_theme_with_fonts() + local def = { + name = "Font Theme", + fonts = { + default = "path/to/font.ttf", + }, + } + local theme = Theme.new(def) + luaunit.assertNotNil(theme) + luaunit.assertNotNil(theme.fonts.default) + luaunit.assertEquals(theme.fonts.default, "path/to/font.ttf") +end + +function TestThemeNew:test_new_theme_with_multiplier() + local def = { + name = "Multiplier Theme", + contentAutoSizingMultiplier = { + width = 1.5, + height = 2.0, + }, + } + local theme = Theme.new(def) + luaunit.assertNotNil(theme) + luaunit.assertNotNil(theme.contentAutoSizingMultiplier) + luaunit.assertEquals(theme.contentAutoSizingMultiplier.width, 1.5) + luaunit.assertEquals(theme.contentAutoSizingMultiplier.height, 2.0) +end + +function TestThemeNew:test_new_theme_without_name_fails() + local def = {} + luaunit.assertErrorMsgContains("name", function() + Theme.new(def) + end) +end + +function TestThemeNew:test_new_theme_with_nil_fails() + luaunit.assertErrorMsgContains("nil", function() + Theme.new(nil) + end) +end + +function TestThemeNew:test_new_theme_with_non_table_fails() + luaunit.assertErrorMsgContains("table", function() + Theme.new("not a table") + end) +end + +-- Test suite for Theme registration and retrieval +TestThemeRegistration = {} + +function TestThemeRegistration:test_setActive_with_theme_object() + local def = { + name = "Active Theme", + } + local theme = Theme.new(def) + Theme.setActive(theme) + + local active = Theme.getActive() + luaunit.assertNotNil(active) + luaunit.assertEquals(active.name, "Active Theme") +end + +function TestThemeRegistration:test_getActive_returns_nil_initially() + -- This test assumes no theme is active, but other tests may have set one + -- So we'll just check that getActive returns something or nil + local active = Theme.getActive() + -- Just verify it doesn't error + luaunit.assertTrue(active == nil or type(active) == "table") +end + +function TestThemeRegistration:test_hasActive_returns_boolean() + local hasActive = Theme.hasActive() + luaunit.assertTrue(type(hasActive) == "boolean") +end + +function TestThemeRegistration:test_get_returns_nil_for_unregistered_theme() + -- Theme.get() looks up themes in the registered themes table + -- Themes created with Theme.new() and setActive() are not automatically registered + local def = { + name = "Unregistered Theme", + } + local theme = Theme.new(def) + Theme.setActive(theme) + + -- This should return nil because the theme was not loaded from a file + local retrieved = Theme.get("Unregistered Theme") + luaunit.assertNil(retrieved) +end + +function TestThemeRegistration:test_get_returns_nil_for_nonexistent() + local retrieved = Theme.get("Nonexistent Theme 12345") + luaunit.assertNil(retrieved) +end + +function TestThemeRegistration:test_getRegisteredThemes_returns_table() + local themes = Theme.getRegisteredThemes() + luaunit.assertNotNil(themes) + luaunit.assertEquals(type(themes), "table") +end + +-- Test suite for Theme.getComponent() +TestThemeComponent = {} + +function TestThemeComponent:setUp() + -- Create and set an active theme with components + local def = { + name = "Component Test Theme", + components = { + button = { + atlas = "path/to/button.png", + }, + panel = { + atlas = "path/to/panel.png", + }, + }, + } + self.theme = Theme.new(def) + Theme.setActive(self.theme) +end + +function TestThemeComponent:test_getComponent_returns_component() + local component = Theme.getComponent("button") + luaunit.assertNotNil(component) + luaunit.assertEquals(component.atlas, "path/to/button.png") +end + +function TestThemeComponent:test_getComponent_returns_nil_for_nonexistent() + local component = Theme.getComponent("nonexistent") + luaunit.assertNil(component) +end + +function TestThemeComponent:test_getComponent_with_state() + -- Add a component with states + local def = { + name = "State Test Theme", + components = { + button = { + atlas = "path/to/button.png", + states = { + hover = { + atlas = "path/to/button_hover.png", + }, + }, + }, + }, + } + local theme = Theme.new(def) + Theme.setActive(theme) + + local component = Theme.getComponent("button", "hover") + luaunit.assertNotNil(component) + luaunit.assertEquals(component.atlas, "path/to/button_hover.png") +end + +-- Test suite for Theme.getColor() +TestThemeColor = {} + +function TestThemeColor:setUp() + local def = { + name = "Color Test Theme", + colors = { + primary = Color.new(1, 0, 0, 1), + secondary = Color.new(0, 1, 0, 1), + textColor = Color.new(0.5, 0.5, 0.5, 1), + }, + } + self.theme = Theme.new(def) + Theme.setActive(self.theme) +end + +function TestThemeColor:test_getColor_returns_color() + local color = Theme.getColor("primary") + luaunit.assertNotNil(color) + luaunit.assertEquals(color.r, 1) + luaunit.assertEquals(color.g, 0) + luaunit.assertEquals(color.b, 0) +end + +function TestThemeColor:test_getColor_returns_nil_for_nonexistent() + local color = Theme.getColor("nonexistent") + luaunit.assertNil(color) +end + +function TestThemeColor:test_getColorNames_returns_table() + local names = Theme.getColorNames() + luaunit.assertNotNil(names) + luaunit.assertEquals(type(names), "table") + -- Should contain our defined colors + luaunit.assertTrue(#names >= 3) +end + +function TestThemeColor:test_getAllColors_returns_table() + local colors = Theme.getAllColors() + luaunit.assertNotNil(colors) + luaunit.assertEquals(type(colors), "table") + luaunit.assertNotNil(colors.primary) + luaunit.assertNotNil(colors.secondary) +end + +function TestThemeColor:test_getColorOrDefault_returns_color() + local color = Theme.getColorOrDefault("primary", Color.new(0, 0, 0, 1)) + luaunit.assertNotNil(color) + luaunit.assertEquals(color.r, 1) +end + +function TestThemeColor:test_getColorOrDefault_returns_fallback() + local fallback = Color.new(0.1, 0.2, 0.3, 1) + local color = Theme.getColorOrDefault("nonexistent", fallback) + luaunit.assertNotNil(color) + luaunit.assertEquals(color.r, 0.1) + luaunit.assertEquals(color.g, 0.2) + luaunit.assertEquals(color.b, 0.3) +end + +-- Test suite for Theme.getFont() +TestThemeFont = {} + +function TestThemeFont:setUp() + local def = { + name = "Font Test Theme", + fonts = { + default = "path/to/default.ttf", + heading = "path/to/heading.ttf", + }, + } + self.theme = Theme.new(def) + Theme.setActive(self.theme) +end + +function TestThemeFont:test_getFont_returns_font_path() + local font = Theme.getFont("default") + luaunit.assertNotNil(font) + luaunit.assertEquals(font, "path/to/default.ttf") +end + +function TestThemeFont:test_getFont_returns_nil_for_nonexistent() + local font = Theme.getFont("nonexistent") + luaunit.assertNil(font) +end + -- Test Suite for Theme Validation TestThemeValidation = {} diff --git a/testing/runAll.lua b/testing/runAll.lua index c97187b..9fea7cd 100644 --- a/testing/runAll.lua +++ b/testing/runAll.lua @@ -21,13 +21,11 @@ local luaunit = require("testing.luaunit") -- Run all tests in the __tests__ directory local testFiles = { "testing/__tests__/utils_test.lua", - "testing/__tests__/sanitization_test.lua", - "testing/__tests__/path_validation_test.lua", - "testing/__tests__/color_validation_test.lua", - "testing/__tests__/texteditor_sanitization_test.lua", - "testing/__tests__/theme_validation_test.lua", - "testing/__tests__/theme_core_test.lua", "testing/__tests__/units_test.lua", + "testing/__tests__/color_validation_test.lua", + "testing/__tests__/path_validation_test.lua", + "testing/__tests__/sanitization_test.lua", + "testing/__tests__/theme_test.lua", "testing/__tests__/layout_engine_test.lua", "testing/__tests__/element_test.lua", }