From d5f85e82d149d58f9c598c0267e9f6356b59cde7 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Thu, 18 Sep 2025 18:27:57 -0400 Subject: [PATCH] tests --- FlexLove.lua | 35 +-- testing/__tests__/01_absolute_positioning.lua | 142 ++++++++++ testing/__tests__/02_flex_direction.lua | 217 ++++++++++++++ .../__tests__/03_vertical_flex_direction.lua | 175 ++++++++++++ testing/__tests__/04_justify_content.lua | 206 ++++++++++++++ testing/__tests__/05_align_items.lua | 168 +++++++++++ testing/__tests__/06_flex_wrap.lua | 234 +++++++++++++++ testing/__tests__/07_layout_validation.lua | 267 ++++++++++++++++++ testing/__tests__/08_performance.lua | 211 ++++++++++++++ testing/__tests__/09_element_properties.lua | 230 +++++++++++++++ .../__tests__/10_animation_and_transform.lua | 216 ++++++++++++++ testing/__tests__/11_auxiliary_functions.lua | 250 ++++++++++++++++ testing/__tests__/README.md | 135 +++++++++ testing/runAll.lua | 42 +++ 14 files changed, 2511 insertions(+), 17 deletions(-) create mode 100644 testing/__tests__/01_absolute_positioning.lua create mode 100644 testing/__tests__/02_flex_direction.lua create mode 100644 testing/__tests__/03_vertical_flex_direction.lua create mode 100644 testing/__tests__/04_justify_content.lua create mode 100644 testing/__tests__/05_align_items.lua create mode 100644 testing/__tests__/06_flex_wrap.lua create mode 100644 testing/__tests__/07_layout_validation.lua create mode 100644 testing/__tests__/08_performance.lua create mode 100644 testing/__tests__/09_element_properties.lua create mode 100644 testing/__tests__/10_animation_and_transform.lua create mode 100644 testing/__tests__/11_auxiliary_functions.lua create mode 100644 testing/__tests__/README.md create mode 100644 testing/runAll.lua diff --git a/FlexLove.lua b/FlexLove.lua index eea13fc..e5a89a1 100644 --- a/FlexLove.lua +++ b/FlexLove.lua @@ -596,21 +596,21 @@ function Element:layoutChildren() goto continue end - if self.flexDirection == FlexDirection.VERTICAL then - -- Position relative to parent origin - child.x = self.x + (self.margin.left or 0) - child.y = self.y + currentPos + if self.flexDirection == FlexDirection.VERTICAL then + -- Position relative to parent origin + child.x = self.x + (self.padding.left or 0) + child.y = self.y + currentPos + (self.padding.top or 0) - -- Apply alignment to vertical axis (alignItems) - if self.alignItems == AlignItems.FLEX_START then - -- nothing - elseif self.alignItems == AlignItems.CENTER then - child.x = self.x + (self.width - (child.width or 0)) / 2 - elseif self.alignItems == AlignItems.FLEX_END then - child.x = self.x + self.width - (child.width or 0) - elseif self.alignItems == AlignItems.STRETCH then - child.width = self.width - end + -- Apply alignment to vertical axis (alignItems) + if self.alignItems == AlignItems.FLEX_START then + -- nothing + elseif self.alignItems == AlignItems.CENTER then + child.x = self.x + ((self.width - (child.width or 0)) / 2) + elseif self.alignItems == AlignItems.FLEX_END then + child.x = self.x + self.width - (child.width or 0) + elseif self.alignItems == AlignItems.STRETCH then + child.width = self.width + end -- Apply self alignment to cross axis (alignSelf) local effectiveAlignSelf = child.alignSelf @@ -650,8 +650,8 @@ function Element:layoutChildren() currentPos = currentPos + (child.height or 0) + self.gap + (self.margin.top or 0) + (self.margin.bottom or 0) else -- Horizontal layout: position relative to parent origin - child.x = self.x + currentPos + (self.margin.left or 0) - child.y = self.y + (self.margin.top or 0) + child.x = self.x + self.padding.left + currentPos + child.y = self.y + self.padding.top -- Determine effective alignment - alignSelf takes precedence over alignItems local effectiveAlign = child.alignSelf @@ -663,7 +663,8 @@ function Element:layoutChildren() if effectiveAlign == AlignItems.FLEX_START then -- Keep the margin.top position (already applied) elseif effectiveAlign == AlignItems.CENTER then - child.y = self.y + (self.height - (child.height or 0)) / 2 + -- Account for parent's margin when centering vertically + child.y = self.y + ((self.height - (child.height or 0)) / 2) elseif effectiveAlign == AlignItems.FLEX_END then child.y = self.y + self.height - (child.height or 0) elseif effectiveAlign == AlignItems.STRETCH then diff --git a/testing/__tests__/01_absolute_positioning.lua b/testing/__tests__/01_absolute_positioning.lua new file mode 100644 index 0000000..6cc8935 --- /dev/null +++ b/testing/__tests__/01_absolute_positioning.lua @@ -0,0 +1,142 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +-- Create test cases +TestAbsolutePositioning = {} + +function TestAbsolutePositioning:setUp() + -- Reset layout engine before each test + self.GUI = FlexLove.GUI +end + +function TestAbsolutePositioning:testBasicAbsolutePositioning() + -- Test basic absolute positioning - similar to CSS position: absolute + local element = self.GUI.new({ + x = 100, + y = 150, + w = 200, + h = 100, + positioning = FlexLove.enums.Positioning.ABSOLUTE, + }) + + luaunit.assertEquals(element.x, 100) + luaunit.assertEquals(element.y, 150) + luaunit.assertEquals(element.width, 200) + luaunit.assertEquals(element.height, 100) + luaunit.assertEquals(element.positioning, FlexLove.enums.Positioning.ABSOLUTE) +end + +function TestAbsolutePositioning:testAbsolutePositioningWithOffsets() + -- Test absolute positioning with top/left/right/bottom - like CSS absolute positioning + local container = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 500, + }) + + local child = self.GUI.new({ + parent = container, + x = 50, + y = 75, + w = 100, + h = 50, + positioning = FlexLove.enums.Positioning.ABSOLUTE, + }) + + -- Element should maintain its absolute position + luaunit.assertEquals(child.x, 50) + luaunit.assertEquals(child.y, 75) + luaunit.assertEquals(child.width, 100) + luaunit.assertEquals(child.height, 50) +end + +function TestAbsolutePositioning:testAbsolutePositioningInContainer() + -- Test absolute positioning within a container - similar to CSS relative container + local container = self.GUI.new({ + x = 100, + y = 100, + w = 500, + h = 500, + }) + + local child = self.GUI.new({ + parent = container, + x = 50, + y = 50, + w = 100, + h = 100, + positioning = FlexLove.enums.Positioning.ABSOLUTE, + }) + + -- Child should keep its absolute position + luaunit.assertEquals(child.x, 50) + luaunit.assertEquals(child.y, 50) + luaunit.assertEquals(child.width, 100) + luaunit.assertEquals(child.height, 100) +end + +function TestAbsolutePositioning:testAbsolutePositioningWithRightBottom() + -- Test absolute positioning with right/bottom properties - like CSS + local container = self.GUI.new({ + x = 0, + y = 0, + w = 1000, + h = 800, + }) + + local child = self.GUI.new({ + parent = container, + x = 850, + y = 650, + w = 100, + h = 100, + positioning = FlexLove.enums.Positioning.ABSOLUTE, + }) + + -- Child should maintain its position from right/bottom edges + luaunit.assertEquals(child.x, 850) + luaunit.assertEquals(child.y, 650) + luaunit.assertEquals(child.width, 100) + luaunit.assertEquals(child.height, 100) +end + +function TestAbsolutePositioning:testAbsolutePositioningZIndex() + -- Test z-index with absolute positioning - like CSS z-index + local container = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 500, + }) + + local child1 = self.GUI.new({ + parent = container, + x = 0, + y = 0, + w = 100, + h = 100, + z = 1, + positioning = FlexLove.enums.Positioning.ABSOLUTE, + }) + + local child2 = self.GUI.new({ + parent = container, + x = 50, + y = 50, + w = 100, + h = 100, + z = 2, + positioning = FlexLove.enums.Positioning.ABSOLUTE, + }) + + -- Elements should maintain their z-index order + luaunit.assertEquals(child1.z, 1) + luaunit.assertEquals(child2.z, 2) + luaunit.assertTrue(child1.z < child2.z) +end + +luaunit.LuaUnit.run() diff --git a/testing/__tests__/02_flex_direction.lua b/testing/__tests__/02_flex_direction.lua new file mode 100644 index 0000000..9520c2b --- /dev/null +++ b/testing/__tests__/02_flex_direction.lua @@ -0,0 +1,217 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +local FlexDirection = FlexLove.enums.FlexDirection +local Positioning = FlexLove.enums.Positioning +local JustifyContent = FlexLove.enums.JustifyContent +local AlignItems = FlexLove.enums.AlignItems + +-- Create test cases +TestFlexDirection = {} + +function TestFlexDirection:setUp() + self.GUI = FlexLove.GUI +end + +function TestFlexDirection:testHorizontalFlexBasic() + -- Test basic horizontal flex layout - like CSS flex-direction: row + local container = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + }) + + -- Add three children with equal widths + local child1 = self.GUI.new({ + parent = container, + w = 100, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 100, + h = 50, + positioning = Positioning.FLEX, + }) + + local child3 = self.GUI.new({ + parent = container, + w = 100, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Elements should be positioned horizontally with default gap of 10 + luaunit.assertEquals(child1.x, 0) -- First child starts at container's x + luaunit.assertEquals(child2.x, 110) -- Second child starts after first child + gap + luaunit.assertEquals(child3.x, 220) -- Third child starts after second child + gap + + -- All children should maintain their original widths + luaunit.assertEquals(child1.width, 100) + luaunit.assertEquals(child2.width, 100) + luaunit.assertEquals(child3.width, 100) +end + +function TestFlexDirection:testHorizontalFlexWithJustifyContentFlexStart() + local container = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.FLEX_START, + }) + + -- Add three children + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Children should be positioned at the start with default gap + luaunit.assertEquals(child1.x, 0) + luaunit.assertEquals(child2.x, 60) +end + +function TestFlexDirection:testHorizontalFlexWithJustifyContentCenter() + local container = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.CENTER, + }) + + -- Add three children + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Children should be centered in container + -- Total width used: 50 + 10 + 50 = 110px + -- Remaining space: 500 - 110 = 390px + -- Space before first child: 390/2 = 195px + luaunit.assertEquals(child1.x, 195) + luaunit.assertEquals(child2.x, 255) -- 195 + 50 + 10 +end + +function TestFlexDirection:testHorizontalFlexWithJustifyContentFlexEnd() + local container = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.FLEX_END, + }) + + -- Add two children + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Children should be positioned at the end + -- Total width used: 50 + 10 + 50 = 110px + -- First child should start at: 500 - 110 = 390px + luaunit.assertEquals(child1.x, 390) + luaunit.assertEquals(child2.x, 450) -- 390 + 50 + 10 +end + +function TestFlexDirection:testHorizontalFlexWithJustifyContentSpaceBetween() + local container = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.SPACE_BETWEEN, + }) + + -- Add two children + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Children should be positioned at the edges + luaunit.assertEquals(child1.x, 0) + luaunit.assertEquals(child2.x, 450) +end + +function TestFlexDirection:testHorizontalFlexWithAlignItemsCenter() + local container = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignItems = AlignItems.CENTER, + }) + + -- Add a child shorter than the container + local child = self.GUI.new({ + parent = container, + w = 50, + h = 50, -- Container is 100px high, child is 50px + positioning = Positioning.FLEX, + }) + + -- Child should be vertically centered + -- Container height: 100px, Child height: 50px + -- Expected y: (100 - 50) / 2 = 25px + luaunit.assertEquals(child.y, 25) +end + +luaunit.LuaUnit.run() diff --git a/testing/__tests__/03_vertical_flex_direction.lua b/testing/__tests__/03_vertical_flex_direction.lua new file mode 100644 index 0000000..f649197 --- /dev/null +++ b/testing/__tests__/03_vertical_flex_direction.lua @@ -0,0 +1,175 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +local FlexDirection = FlexLove.enums.FlexDirection +local Positioning = FlexLove.enums.Positioning +local JustifyContent = FlexLove.enums.JustifyContent +local AlignItems = FlexLove.enums.AlignItems + +-- Create test cases +TestVerticalFlexDirection = {} + +function TestVerticalFlexDirection:setUp() + self.GUI = FlexLove.GUI +end + +function TestVerticalFlexDirection:testVerticalFlexBasic() + -- Test basic vertical flex layout - like CSS flex-direction: column + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 500, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + }) + + -- Add three children with equal heights + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 100, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 100, + positioning = Positioning.FLEX, + }) + + local child3 = self.GUI.new({ + parent = container, + w = 50, + h = 100, + positioning = Positioning.FLEX, + }) + + -- Elements should be positioned vertically with default gap of 10 + luaunit.assertEquals(child1.y, 0) + luaunit.assertEquals(child2.y, 110) + luaunit.assertEquals(child3.y, 220) + + -- All children should maintain their original heights + luaunit.assertEquals(child1.height, 100) + luaunit.assertEquals(child2.height, 100) + luaunit.assertEquals(child3.height, 100) +end + +function TestVerticalFlexDirection:testVerticalFlexWithJustifyContentFlexStart() + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 500, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + justifyContent = JustifyContent.FLEX_START, + }) + + -- Add two children + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Children should be positioned at the start with default gap + luaunit.assertEquals(child1.y, 0) + luaunit.assertEquals(child2.y, 60) +end + +function TestVerticalFlexDirection:testVerticalFlexWithJustifyContentCenter() + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 500, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + justifyContent = JustifyContent.CENTER, + }) + + -- Add two children + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Children should be centered in container + -- Total height used: 50 + 10 + 50 = 110px + -- Remaining space: 500 - 110 = 390px + -- Space before first child: 390/2 = 195px + luaunit.assertEquals(child1.y, 195) + luaunit.assertEquals(child2.y, 255) +end + +function TestVerticalFlexDirection:testVerticalFlexWithAlignItemsCenter() + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 500, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + alignItems = AlignItems.CENTER, + }) + + -- Add a child narrower than the container + local child = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Child should be horizontally centered + -- Container width: 100px, Child width: 50px + -- Expected x: (100 - 50) / 2 = 25px + luaunit.assertEquals(child.x, 25) +end + +function TestVerticalFlexDirection:testVerticalFlexWithAlignItemsStretch() + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 500, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + alignItems = AlignItems.STRETCH, + }) + + -- Add a child without explicit width + local child = self.GUI.new({ + parent = container, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Child should stretch to container width + luaunit.assertEquals(child.width, 100) +end + +luaunit.LuaUnit.run() diff --git a/testing/__tests__/04_justify_content.lua b/testing/__tests__/04_justify_content.lua new file mode 100644 index 0000000..fdbc0cd --- /dev/null +++ b/testing/__tests__/04_justify_content.lua @@ -0,0 +1,206 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +local FlexDirection = FlexLove.enums.FlexDirection +local Positioning = FlexLove.enums.Positioning +local JustifyContent = FlexLove.enums.JustifyContent + +-- Create test cases +TestJustifyContent = {} + +function TestJustifyContent:setUp() + self.GUI = FlexLove.GUI +end + +function TestJustifyContent:testJustifyContentSpaceEvenly() + -- Test space-evenly distribution in horizontal layout + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.SPACE_EVENLY, + }) + + -- Add three children of equal width + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child3 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Calculate expected positions + -- Total width of children: 150px (3 * 50px) + -- Remaining space: 150px (300px - 150px) + -- Space between and around items: 150px / 4 = 37.5px + luaunit.assertEquals(child1.x, 37) -- First space + luaunit.assertEquals(child2.x, 125) -- First space + width + second space + luaunit.assertEquals(child3.x, 212) -- Previous + width + third space +end + +function TestJustifyContent:testJustifyContentSpaceAround() + -- Test space-around distribution + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.SPACE_AROUND, + }) + + -- Add two children with equal widths + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Calculate expected positions + -- Total width of children: 100px (2 * 50px) + -- Remaining space: 200px (300px - 100px) + -- Space around each item: 200px / 4 = 50px + -- First item gets 50px margin, second gets 150px (50px * 3) margin + luaunit.assertEquals(child1.x, 50) + luaunit.assertEquals(child2.x, 200) +end + +function TestJustifyContent:testJustifyContentSpaceBetween() + -- Test space-between distribution + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.SPACE_BETWEEN, + }) + + -- Add three children + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child3 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Calculate expected positions + -- Total width of children: 150px (3 * 50px) + -- Remaining space: 150px (300px - 150px) + -- Space between items: 75px (150px / 2) + luaunit.assertEquals(child1.x, 0) -- First child at start + luaunit.assertEquals(child2.x, 125) -- After first gap + luaunit.assertEquals(child3.x, 250) -- After second gap +end + +function TestJustifyContent:testJustifyContentFlexStart() + -- Test flex-start alignment + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.FLEX_START, + }) + + -- Add two children + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Children should be at the start with default gap + luaunit.assertEquals(child1.x, 0) -- First child at start + luaunit.assertEquals(child2.x, 60) -- After first child + gap +end + +function TestJustifyContent:testJustifyContentFlexEnd() + -- Test flex-end alignment + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.FLEX_END, + }) + + -- Add two children + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Children should be at the end with default gap + -- Total width needed: 110px (50px + 10px + 50px) + -- Start position: 300px - 110px = 190px + luaunit.assertEquals(child1.x, 190) + luaunit.assertEquals(child2.x, 250) +end + +luaunit.LuaUnit.run() diff --git a/testing/__tests__/05_align_items.lua b/testing/__tests__/05_align_items.lua new file mode 100644 index 0000000..f865503 --- /dev/null +++ b/testing/__tests__/05_align_items.lua @@ -0,0 +1,168 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +local FlexDirection = FlexLove.enums.FlexDirection +local Positioning = FlexLove.enums.Positioning +local AlignItems = FlexLove.enums.AlignItems + +-- Create test cases +TestAlignItems = {} + +function TestAlignItems:setUp() + self.GUI = FlexLove.GUI +end + +function TestAlignItems:testAlignItemsStretchHorizontal() + -- Test stretch alignment in horizontal layout + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignItems = AlignItems.STRETCH, + }) + + -- Add child without explicit height + local child = self.GUI.new({ + parent = container, + w = 50, + positioning = Positioning.FLEX, + }) + + -- Child should stretch to container height + luaunit.assertEquals(child.height, container.height) +end + +function TestAlignItems:testAlignItemsStretchVertical() + -- Test stretch alignment in vertical layout + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 300, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + alignItems = AlignItems.STRETCH, + }) + + -- Add child without explicit width + local child = self.GUI.new({ + parent = container, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Child should stretch to container width + luaunit.assertEquals(child.width, container.width) +end + +function TestAlignItems:testAlignItemsCenterHorizontal() + -- Test center alignment in horizontal layout + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignItems = AlignItems.CENTER, + }) + + -- Add child shorter than container + local child = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Child should be vertically centered + -- Container height: 100px, Child height: 50px + -- Expected y: (100 - 50) / 2 = 25px + luaunit.assertEquals(child.y, 25) +end + +function TestAlignItems:testAlignItemsCenterVertical() + -- Test center alignment in vertical layout + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 300, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + alignItems = AlignItems.CENTER, + }) + + -- Add child narrower than container + local child = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Child should be horizontally centered + -- Container width: 100px, Child width: 50px + -- Expected x: (100 - 50) / 2 = 25px + luaunit.assertEquals(child.x, 25) +end + +function TestAlignItems:testAlignItemsFlexStart() + -- Test flex-start alignment in horizontal layout + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignItems = AlignItems.FLEX_START, + }) + + -- Add child shorter than container + local child = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Child should be at the top + luaunit.assertEquals(child.y, 0) +end + +function TestAlignItems:testAlignItemsFlexEnd() + -- Test flex-end alignment in horizontal layout + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignItems = AlignItems.FLEX_END, + }) + + -- Add child shorter than container + local child = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Child should be at the bottom + -- Container height: 100px, Child height: 50px + -- Expected y: 100px - 50px = 50px + luaunit.assertEquals(child.y, 50) +end + +-- Run the test suite +os.exit(luaunit.LuaUnit.run()) + diff --git a/testing/__tests__/06_flex_wrap.lua b/testing/__tests__/06_flex_wrap.lua new file mode 100644 index 0000000..a4a83fe --- /dev/null +++ b/testing/__tests__/06_flex_wrap.lua @@ -0,0 +1,234 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +local FlexDirection = FlexLove.enums.FlexDirection +local Positioning = FlexLove.enums.Positioning +local AlignContent = FlexLove.enums.AlignContent + +-- Create test cases +TestFlexWrap = {} + +function TestFlexWrap:setUp() + self.GUI = FlexLove.GUI +end + +function TestFlexWrap:testFlexWrapHorizontal() + -- Test flex wrap in horizontal layout + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 300, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignContent = AlignContent.FLEX_START, + }) + + -- Add three children that exceed container width + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child3 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- First line: child1 and child2 (with 10px gap) + -- Second line: child3 + luaunit.assertEquals(child1.x, 0) + luaunit.assertEquals(child1.y, 0) + luaunit.assertEquals(child2.x, 60) + luaunit.assertEquals(child2.y, 0) + luaunit.assertEquals(child3.x, 0) + luaunit.assertEquals(child3.y, 60) +end + +function TestFlexWrap:testFlexWrapVertical() + -- Test flex wrap in vertical layout + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + alignContent = AlignContent.FLEX_START, + }) + + -- Add three children that exceed container height + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child3 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- First column: child1 and child2 (with 10px gap) + -- Second column: child3 + luaunit.assertEquals(child1.x, 0) + luaunit.assertEquals(child1.y, 0) + luaunit.assertEquals(child2.x, 0) + luaunit.assertEquals(child2.y, 60) + luaunit.assertEquals(child3.x, 60) + luaunit.assertEquals(child3.y, 0) +end + +function TestFlexWrap:testFlexWrapWithAlignContentCenter() + -- Test align-content center with flex wrap + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 300, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignContent = AlignContent.CENTER, + }) + + -- Add three children that create two rows + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child3 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Total height used: 110px (two rows of 50px + 10px gap) + -- Remaining space: 190px (300px - 110px) + -- Space before first row: 95px (190px / 2) + luaunit.assertEquals(child1.y, 95) + luaunit.assertEquals(child2.y, 95) + luaunit.assertEquals(child3.y, 155) -- 95px + 50px + 10px gap +end + +function TestFlexWrap:testFlexWrapWithAlignContentSpaceBetween() + -- Test align-content space-between with flex wrap + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 300, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignContent = AlignContent.SPACE_BETWEEN, + }) + + -- Add three children that create two rows + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child3 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- First row at top (y = 0) + -- Second row at bottom (y = 250) + luaunit.assertEquals(child1.y, 0) + luaunit.assertEquals(child2.y, 0) + luaunit.assertEquals(child3.y, 250) +end + +function TestFlexWrap:testFlexWrapWithAlignContentSpaceAround() + -- Test align-content space-around with flex wrap + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 300, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignContent = AlignContent.SPACE_AROUND, + }) + + -- Add three children that create two rows + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child3 = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Space around calculation: + -- Total height of content: 110px (two rows of 50px + 10px gap) + -- Remaining space: 190px + -- Space per unit: 63.33px (190px / 3) + -- First row: 63.33px (one unit of space) + -- Second row: 190px (three units of space) + luaunit.assertEquals(child1.y, 63) + luaunit.assertEquals(child2.y, 63) + luaunit.assertEquals(child3.y, 190) +end + +luaunit.LuaUnit.run() diff --git a/testing/__tests__/07_layout_validation.lua b/testing/__tests__/07_layout_validation.lua new file mode 100644 index 0000000..0daeae3 --- /dev/null +++ b/testing/__tests__/07_layout_validation.lua @@ -0,0 +1,267 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +local FlexDirection = FlexLove.enums.FlexDirection +local Positioning = FlexLove.enums.Positioning +local JustifyContent = FlexLove.enums.JustifyContent +local AlignItems = FlexLove.enums.AlignItems + +-- Create test cases +TestLayoutValidation = {} + +function TestLayoutValidation:setUp() + self.GUI = FlexLove.GUI +end + +function TestLayoutValidation:testNestedFlexContainers() + -- Test nested flex containers behave correctly + local outerContainer = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 300, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + }) + + local innerContainer1 = self.GUI.new({ + parent = outerContainer, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.SPACE_BETWEEN, + }) + + local innerContainer2 = self.GUI.new({ + parent = outerContainer, + w = 300, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.CENTER, + }) + + -- Add children to inner container 1 + local child1 = self.GUI.new({ + parent = innerContainer1, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = innerContainer1, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Add child to inner container 2 + local child3 = self.GUI.new({ + parent = innerContainer2, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Verify outer container layout + luaunit.assertEquals(innerContainer1.y, 0) + luaunit.assertEquals(innerContainer2.y, 110) -- 100 + 10 gap + + -- Verify inner container 1 layout (space-between) + luaunit.assertEquals(child1.x, 0) + luaunit.assertEquals(child2.x, 250) + + -- Verify inner container 2 layout (center) + luaunit.assertEquals(child3.x, 125) -- (300 - 50) / 2 + + -- Test container references + luaunit.assertEquals(#innerContainer1.children, 2) + luaunit.assertEquals(#innerContainer2.children, 1) + luaunit.assertEquals(innerContainer1.children[1], child1) + luaunit.assertEquals(innerContainer1.children[2], child2) + luaunit.assertEquals(innerContainer2.children[1], child3) +end + +function TestLayoutValidation:testMixedPositioning() + -- Test mixing absolute and flex positioning + local container = self.GUI.new({ + x = 0, + y = 0, + w = 300, + h = 300, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + }) + + -- Add flex positioned child + local flexChild = self.GUI.new({ + parent = container, + w = 100, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Add absolute positioned child + local absoluteChild = self.GUI.new({ + parent = container, + x = 150, + y = 150, + w = 100, + h = 50, + positioning = Positioning.ABSOLUTE, + }) + + -- Add another flex positioned child + local flexChild2 = self.GUI.new({ + parent = container, + w = 100, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Verify flex children positions + luaunit.assertEquals(flexChild.y, 0) + luaunit.assertEquals(flexChild2.y, 60) -- 50 + 10 gap + + -- Verify absolute child position is maintained + luaunit.assertEquals(absoluteChild.x, 150) + luaunit.assertEquals(absoluteChild.y, 150) +end + +function TestLayoutValidation:testDynamicSizing() + -- Test auto-sizing of flex containers + local container = self.GUI.new({ + x = 0, + y = 0, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + }) + + -- Add children to determine container size + local child1 = self.GUI.new({ + parent = container, + w = 50, + h = 100, + positioning = Positioning.FLEX, + }) + + local child2 = self.GUI.new({ + parent = container, + w = 50, + h = 150, + positioning = Positioning.FLEX, + }) + + -- Container should size to fit children + luaunit.assertEquals(container.width, 110) -- 50 + 10 + 50 + luaunit.assertEquals(container.height, 150) -- Max of child heights +end + +function TestLayoutValidation:testDeepNesting() + -- Test deeply nested flex containers + local level1 = self.GUI.new({ + x = 0, + y = 0, + w = 400, + h = 400, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + }) + + local level2 = self.GUI.new({ + parent = level1, + w = 300, + h = 300, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + }) + + local level3 = self.GUI.new({ + parent = level2, + w = 200, + h = 200, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + alignItems = AlignItems.CENTER, + }) + + local level4 = self.GUI.new({ + parent = level3, + w = 100, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.CENTER, + }) + + -- Add a child to the deepest level + local deepChild = self.GUI.new({ + parent = level4, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + + -- Verify positioning through all levels + luaunit.assertEquals(level2.y, 0) + luaunit.assertEquals(level3.x, 0) + luaunit.assertEquals(level4.x, 50) -- (200 - 100) / 2 + luaunit.assertEquals(deepChild.x, 25) -- (100 - 50) / 2 +end + +function TestLayoutValidation:testEdgeCases() + -- Test edge cases and potential layout issues + local container = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + }) + + -- Test zero-size child + local zeroSizeChild = self.GUI.new({ + parent = container, + w = 0, + h = 0, + positioning = Positioning.FLEX, + }) + + -- Test negative size (should be clamped to 0) + local negativeSizeChild = self.GUI.new({ + parent = container, + w = -50, + h = -50, + positioning = Positioning.FLEX, + }) + + -- Test oversized child + local oversizedChild = self.GUI.new({ + parent = container, + w = 200, + h = 200, + positioning = Positioning.FLEX, + }) + + -- Verify layout handles edge cases gracefully + luaunit.assertTrue(zeroSizeChild.width >= 0) + luaunit.assertTrue(zeroSizeChild.height >= 0) + luaunit.assertTrue(negativeSizeChild.width >= 0) + luaunit.assertTrue(negativeSizeChild.height >= 0) + luaunit.assertEquals(oversizedChild.x, 0) -- Should still be positioned at start + + -- Check that containers handle children properly + luaunit.assertEquals(zeroSizeChild.x, 0) -- First child should be at start + luaunit.assertEquals(negativeSizeChild.x, 0) -- Should be positioned after zero-size child + luaunit.assertEquals(oversizedChild.x, 0) -- Should be positioned after negative-size child + luaunit.assertNotNil(container.children[1]) -- Container should maintain child references + luaunit.assertEquals(#container.children, 3) -- All children should be tracked +end + +luaunit.LuaUnit.run() diff --git a/testing/__tests__/08_performance.lua b/testing/__tests__/08_performance.lua new file mode 100644 index 0000000..ae1254e --- /dev/null +++ b/testing/__tests__/08_performance.lua @@ -0,0 +1,211 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +-- Import only the enum values we need for each test +local FlexDirection = FlexLove.enums.FlexDirection +local Positioning = FlexLove.enums.Positioning +local JustifyContent = FlexLove.enums.JustifyContent +local AlignItems = FlexLove.enums.AlignItems + +-- Create test cases +TestPerformance = {} + +function TestPerformance:setUp() + self.GUI = FlexLove.GUI +end + +-- Helper function to measure execution time +local function measure(fn) + local start = os.clock() + fn() + return os.clock() - start +end + +function TestPerformance:testLargeNumberOfChildren() + -- Test performance with a large number of children + local container = self.GUI.new({ + x = 0, + y = 0, + w = 1000, + h = 1000, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.FLEX_START, + }) + + -- Create 100 children + local createTime = measure(function() + for _ = 1, 100 do + self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + end + end) + + -- Print creation time for visibility + print(string.format("Creating 100 children took: %.4f seconds", createTime)) + + -- Verify container has all children + luaunit.assertEquals(#container.children, 100) + + -- Performance should be reasonable (adjust threshold based on target hardware) + luaunit.assertTrue(createTime < 1.0, "Creating children took too long: " .. createTime) + + -- Test layout time (with nil check) + local layoutTime = measure(function() + luaunit.assertNotNil(container.layoutChildren, "layoutChildren method should exist") + container:layoutChildren() + end) + + -- Print layout time for visibility + print(string.format("Laying out 100 children took: %.4f seconds", layoutTime)) + + -- Layout should be reasonably fast + luaunit.assertTrue(layoutTime < 1.0, "Layout took too long: " .. layoutTime) +end + +function TestPerformance:testDeepHierarchy() + -- Test performance with a deep hierarchy + local root = nil + local rootTime = measure(function() + root = self.GUI.new({ + x = 0, + y = 0, + w = 1000, + h = 1000, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.VERTICAL, + }) + + local current = root + for i = 1, 10 do + current = self.GUI.new({ + parent = current, + w = 900 - (i * 50), + h = 900 - (i * 50), + positioning = Positioning.FLEX, + flexDirection = i % 2 == 0 and FlexDirection.HORIZONTAL or FlexDirection.VERTICAL, + }) + + -- Add some siblings at each level + for _ = 1, 3 do + self.GUI.new({ + parent = current, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + end + end + end) + + -- Print creation time for visibility + print(string.format("Creating deep hierarchy took: %.4f seconds", rootTime)) + + -- Creation should be reasonably fast + luaunit.assertTrue(rootTime < 1.0, "Creating deep hierarchy took too long: " .. rootTime) + + -- Test layout performance (with nil check) + local layoutTime = measure(function() + luaunit.assertNotNil(root.layoutChildren, "layoutChildren method should exist") + root:layoutChildren() + end) + + -- Print layout time for visibility + print(string.format("Laying out deep hierarchy took: %.4f seconds", layoutTime)) + + -- Layout should be reasonably fast + luaunit.assertTrue(layoutTime < 1.0, "Layout took too long: " .. layoutTime) +end + +function TestPerformance:testDynamicUpdates() + -- Test performance of dynamic updates + local container = self.GUI.new({ + x = 0, + y = 0, + w = 1000, + h = 1000, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + alignItems = AlignItems.CENTER, + }) + + -- Create 50 children + local children = {} + for i = 1, 50 do + children[i] = self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + end + + -- Test update performance (resizing children) + local updateTime = measure(function() + for _, child in ipairs(children) do + child.width = child.width + 10 + child.height = child.height + 10 + end + luaunit.assertNotNil(container.layoutChildren, "layoutChildren method should exist") + container:layoutChildren() + end) + + -- Print update time for visibility + print(string.format("Updating 50 children took: %.4f seconds", updateTime)) + + -- Updates should be reasonably fast + luaunit.assertTrue(updateTime < 1.0, "Updates took too long: " .. updateTime) + + -- Verify updates were applied + luaunit.assertEquals(children[1].width, 60) + luaunit.assertEquals(children[1].height, 60) +end + +function TestPerformance:testRapidResizing() + -- Test performance of rapid window resizing + local container = self.GUI.new({ + x = 0, + y = 0, + w = 1000, + h = 1000, + positioning = Positioning.FLEX, + flexDirection = FlexDirection.HORIZONTAL, + justifyContent = JustifyContent.SPACE_BETWEEN, + }) + + -- Add 20 children + for _ = 1, 20 do + self.GUI.new({ + parent = container, + w = 50, + h = 50, + positioning = Positioning.FLEX, + }) + end + + -- Test 10 rapid resizes + local resizeTime = measure(function() + for i = 1, 10 do + container:resize(1000 + i * 100, 1000 + i * 100) + end + end) + + -- Print resize time for visibility + print(string.format("10 rapid resizes took: %.4f seconds", resizeTime)) + + -- Resizing should be reasonably fast + luaunit.assertTrue(resizeTime < 1.0, "Resizing took too long: " .. resizeTime) + + -- Verify final dimensions + luaunit.assertEquals(container.width, 2000) + luaunit.assertEquals(container.height, 2000) +end + +luaunit.LuaUnit.run() diff --git a/testing/__tests__/09_element_properties.lua b/testing/__tests__/09_element_properties.lua new file mode 100644 index 0000000..5c1246e --- /dev/null +++ b/testing/__tests__/09_element_properties.lua @@ -0,0 +1,230 @@ +package.path = package.path .. ";game/libs/?.lua;?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +local Positioning = FlexLove.enums.Positioning +local TextAlign = FlexLove.enums.TextAlign +local Color = FlexLove.Color + +-- Create test cases +TestElementProperties = {} + +function TestElementProperties:setUp() + self.GUI = FlexLove.GUI +end + +function TestElementProperties:testBasicProperties() + local element = self.GUI.new({ + x = 10, + y = 20, + w = 100, + h = 50, + z = 1, + positioning = Positioning.ABSOLUTE, + }) + + -- Test basic properties + luaunit.assertNotNil(element) + luaunit.assertEquals(element.x, 10) + luaunit.assertEquals(element.y, 20) + luaunit.assertEquals(element.z, 1) + luaunit.assertEquals(element.width, 100) + luaunit.assertEquals(element.height, 50) + luaunit.assertEquals(element.positioning, Positioning.ABSOLUTE) +end + +function TestElementProperties:testPropertyModification() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Test property modification + luaunit.assertNotNil(element) + element.x = 50 + element.y = 60 + element.width = 200 + element.height = 150 + + luaunit.assertEquals(element.x, 50) + luaunit.assertEquals(element.y, 60) + luaunit.assertEquals(element.width, 200) + luaunit.assertEquals(element.height, 150) +end + +function TestElementProperties:testParentChildRelationship() + local parent = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 500, + }) + + local child = self.GUI.new({ + parent = parent, + x = 10, + y = 10, + w = 100, + h = 100, + }) + + -- Test parent-child relationship + luaunit.assertNotNil(parent) + luaunit.assertNotNil(child) + luaunit.assertNotNil(parent.children) + luaunit.assertEquals(child.parent, parent) + luaunit.assertTrue(#parent.children == 1) + luaunit.assertEquals(parent.children[1], child) +end + +function TestElementProperties:testBounds() + local element = self.GUI.new({ + x = 10, + y = 20, + w = 100, + h = 50, + }) + + -- Test bounds calculation + luaunit.assertNotNil(element) + luaunit.assertNotNil(element.getBounds) + 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 TestElementProperties:testZLayering() + local parent = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 500, + }) + + local child1 = self.GUI.new({ + parent = parent, + x = 0, + y = 0, + w = 100, + h = 100, + z = 1, + }) + + local child2 = self.GUI.new({ + parent = parent, + x = 0, + y = 0, + w = 100, + h = 100, + z = 2, + }) + + -- Test z ordering + luaunit.assertNotNil(parent) + luaunit.assertNotNil(child1) + luaunit.assertNotNil(child2) + luaunit.assertNotNil(child1.z) + luaunit.assertNotNil(child2.z) + luaunit.assertTrue(child1.z < child2.z) +end + +function TestElementProperties:testColors() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + background = Color.new(1, 0, 0, 1), -- Red + textColor = Color.new(0, 1, 0, 1), -- Green + borderColor = Color.new(0, 0, 1, 1), -- Blue + }) + + -- Test color assignments + luaunit.assertNotNil(element.background) + luaunit.assertEquals(element.background.r, 1) + luaunit.assertEquals(element.background.g, 0) + luaunit.assertEquals(element.background.b, 0) + luaunit.assertEquals(element.background.a, 1) + + luaunit.assertNotNil(element.textColor) + luaunit.assertEquals(element.textColor.r, 0) + luaunit.assertEquals(element.textColor.g, 1) + luaunit.assertEquals(element.textColor.b, 0) + luaunit.assertEquals(element.textColor.a, 1) + + luaunit.assertNotNil(element.borderColor) + luaunit.assertEquals(element.borderColor.r, 0) + luaunit.assertEquals(element.borderColor.g, 0) + luaunit.assertEquals(element.borderColor.b, 1) + luaunit.assertEquals(element.borderColor.a, 1) +end + +function TestElementProperties:testText() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 200, + h = 100, + text = "Test Text", + textSize = 16, + textAlign = TextAlign.CENTER, + }) + + -- Test text properties + luaunit.assertNotNil(element) + luaunit.assertEquals(element.text, "Test Text") + luaunit.assertEquals(element.textSize, 16) + luaunit.assertEquals(element.textAlign, TextAlign.CENTER) + + -- Test text update + element:updateText("New Text", true) + luaunit.assertEquals(element.text, "New Text") +end + +function TestElementProperties:testOpacity() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + opacity = 0.5, + }) + + -- Test opacity property and updates + luaunit.assertNotNil(element) + luaunit.assertEquals(element.opacity, 0.5) + + element:updateOpacity(0.8) + luaunit.assertEquals(element.opacity, 0.8) +end + +function TestElementProperties:testBorder() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + border = { + top = true, + right = true, + bottom = true, + left = true, + }, + }) + + -- Test border configuration + luaunit.assertNotNil(element) + luaunit.assertTrue(element.border.top) + luaunit.assertTrue(element.border.right) + luaunit.assertTrue(element.border.bottom) + luaunit.assertTrue(element.border.left) +end + +luaunit.LuaUnit.run() + diff --git a/testing/__tests__/10_animation_and_transform.lua b/testing/__tests__/10_animation_and_transform.lua new file mode 100644 index 0000000..e3fc873 --- /dev/null +++ b/testing/__tests__/10_animation_and_transform.lua @@ -0,0 +1,216 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +-- Create test cases +TestAnimationAndTransform = {} + +function TestAnimationAndTransform:setUp() + self.GUI = FlexLove.GUI +end + +function TestAnimationAndTransform:testBasicTranslation() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Test translate transformation + luaunit.assertNotNil(element) + luaunit.assertNotNil(element.translate) + element:translate(50, 30) + luaunit.assertEquals(element.x, 50) + luaunit.assertEquals(element.y, 30) +end + +function TestAnimationAndTransform:testScale() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Test scale transformation + luaunit.assertNotNil(element) + luaunit.assertNotNil(element.scale) + element:scale(2, 1.5) + luaunit.assertEquals(element.width, 200) + luaunit.assertEquals(element.height, 150) +end + +function TestAnimationAndTransform:testRotation() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Test rotation transformation (in radians) + luaunit.assertNotNil(element) + luaunit.assertNotNil(element.rotate) + local angle = math.pi / 4 -- 45 degrees + element:rotate(angle) + luaunit.assertNotNil(element.rotation) + luaunit.assertEquals(element.rotation, angle) +end + +function TestAnimationAndTransform:testAnimationTweening() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Start position animation + luaunit.assertNotNil(element) + luaunit.assertNotNil(element.animate) + luaunit.assertNotNil(element.update) + element:animate({ + x = 200, + y = 150, + duration = 1.0, + easing = "linear", + }) + + -- Test initial state + luaunit.assertEquals(element.x, 0) + luaunit.assertEquals(element.y, 0) + + -- Simulate time passing (0.5 seconds) + element:update(0.5) + + -- Test mid-animation state (linear interpolation) + luaunit.assertEquals(element.x, 100) -- Half way there + luaunit.assertEquals(element.y, 75) -- Half way there +end + +function TestAnimationAndTransform:testChainedTransformations() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Apply multiple transformations in sequence + luaunit.assertNotNil(element) + luaunit.assertNotNil(element.translate) + luaunit.assertNotNil(element.scale) + luaunit.assertNotNil(element.rotate) + element:translate(50, 50):scale(2, 2):rotate(math.pi / 2) + + -- Verify final state + luaunit.assertEquals(element.x, 50) + luaunit.assertEquals(element.y, 50) + luaunit.assertEquals(element.width, 200) + luaunit.assertEquals(element.height, 200) + luaunit.assertNotNil(element.rotation) + luaunit.assertEquals(element.rotation, math.pi / 2) +end + +function TestAnimationAndTransform:testAnimationCancellation() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Start animation + luaunit.assertNotNil(element) + luaunit.assertNotNil(element.animate) + luaunit.assertNotNil(element.update) + luaunit.assertNotNil(element.stopAnimation) + element:animate({ + x = 200, + y = 200, + duration = 2.0, + }) + + -- Update partially + element:update(0.5) + + -- Cancel animation + element:stopAnimation() + + -- Position should remain at last updated position + local x = element.x + local y = element.y + + -- Update again to ensure animation stopped + element:update(0.5) + + luaunit.assertEquals(element.x, x) + luaunit.assertEquals(element.y, y) +end + +function TestAnimationAndTransform:testMultiplePropertyAnimation() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + alpha = 1.0, + }) + + -- Animate multiple properties simultaneously + luaunit.assertNotNil(element) + luaunit.assertNotNil(element.animate) + luaunit.assertNotNil(element.update) + element:animate({ + x = 200, + y = 200, + width = 200, + height = 200, + alpha = 0.5, + duration = 1.0, + easing = "linear", + }) + + -- Update halfway + element:update(0.5) + + -- Test all properties at midpoint + luaunit.assertEquals(element.x, 100) + luaunit.assertEquals(element.y, 100) + luaunit.assertEquals(element.width, 150) + luaunit.assertEquals(element.height, 150) + luaunit.assertNotNil(element.alpha) + luaunit.assertEquals(element.alpha, 0.75) +end + +function TestAnimationAndTransform:testEasingFunctions() + local element = self.GUI.new({ + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Test different easing functions + local easings = { "linear", "easeInQuad", "easeOutQuad", "easeInOutQuad" } + + for _, easing in ipairs(easings) do + element.x = 0 + luaunit.assertNotNil(element.animate) + element:animate({ + x = 100, + duration = 1.0, + easing = easing, + }) + + element:update(0.5) + + -- Ensure animation is progressing (exact values depend on easing function) + luaunit.assertTrue(element.x > 0 and element.x < 100) + end +end + +luaunit.LuaUnit.run() diff --git a/testing/__tests__/11_auxiliary_functions.lua b/testing/__tests__/11_auxiliary_functions.lua new file mode 100644 index 0000000..cd412fb --- /dev/null +++ b/testing/__tests__/11_auxiliary_functions.lua @@ -0,0 +1,250 @@ +package.path = package.path .. ";?.lua" + +local luaunit = require("testing/luaunit") +require("testing/loveStub") -- Required to mock LOVE functions +local FlexLove = require("FlexLove") + +-- Create test cases +TestAuxiliaryFunctions = {} + +function TestAuxiliaryFunctions:setUp() + self.GUI = FlexLove.GUI +end + +function TestAuxiliaryFunctions:testFindElementById() + local root = self.GUI.new({ + id = "root", + x = 0, + y = 0, + w = 500, + h = 500, + }) + + local child = self.GUI.new({ + id = "child", + parent = root, + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Test finding elements by ID + luaunit.assertNotNil(self.GUI.findElementById) + local foundRoot = self.GUI:findElementById("root") + local foundChild = self.GUI:findElementById("child") + + luaunit.assertNotNil(foundRoot) + luaunit.assertNotNil(foundChild) + luaunit.assertEquals(foundRoot, root) + luaunit.assertEquals(foundChild, child) +end + +function TestAuxiliaryFunctions:testFindElementsByClass() + local root = self.GUI.new({ + class = "container", + x = 0, + y = 0, + w = 500, + h = 500, + }) + + self.GUI.new({ + class = "item", + parent = root, + x = 0, + y = 0, + w = 100, + h = 100, + }) + + self.GUI.new({ + class = "item", + parent = root, + x = 100, + y = 0, + w = 100, + h = 100, + }) + + -- Test finding elements by class + luaunit.assertNotNil(self.GUI.findElementsByClass) + local items = self.GUI:findElementsByClass("item") + luaunit.assertEquals(#items, 2) + + local containers = self.GUI:findElementsByClass("container") + luaunit.assertEquals(#containers, 1) + luaunit.assertEquals(containers[1], root) +end + +function TestAuxiliaryFunctions:testGetElementsAtPoint() + local root = self.GUI.new({ + x = 0, + y = 0, + w = 500, + h = 500, + }) + + self.GUI.new({ + parent = root, + x = 50, + y = 50, + w = 100, + h = 100, + }) + + self.GUI.new({ + parent = root, + x = 200, + y = 200, + w = 100, + h = 100, + }) + + -- Test getting elements at specific points + luaunit.assertNotNil(self.GUI.getElementsAtPoint) + local elements1 = self.GUI:getElementsAtPoint(75, 75) + local elements2 = self.GUI:getElementsAtPoint(250, 250) + local elements3 = self.GUI:getElementsAtPoint(0, 0) + + luaunit.assertTrue(#elements1 >= 2) -- Should find root and child1 + luaunit.assertTrue(#elements2 >= 2) -- Should find root and child2 + luaunit.assertEquals(#elements3, 1) -- Should only find root +end + +function TestAuxiliaryFunctions:testQuerySelector() + local root = self.GUI.new({ + id = "root", + class = "container", + x = 0, + y = 0, + w = 500, + h = 500, + }) + + self.GUI.new({ + id = "btn1", + class = "button primary", + parent = root, + x = 0, + y = 0, + w = 100, + h = 100, + }) + + self.GUI.new({ + id = "btn2", + class = "button secondary", + parent = root, + x = 100, + y = 0, + w = 100, + h = 100, + }) + + -- Test querySelector functionality + luaunit.assertNotNil(self.GUI.querySelector) + local container = self.GUI:querySelector(".container") + local primaryBtn = self.GUI:querySelector(".button.primary") + local secondaryBtn = self.GUI:querySelector(".button.secondary") + local specificBtn = self.GUI:querySelector("#btn1") + + luaunit.assertNotNil(container) + luaunit.assertNotNil(primaryBtn) + luaunit.assertNotNil(secondaryBtn) + luaunit.assertNotNil(specificBtn) + luaunit.assertEquals(container, root) +end + +function TestAuxiliaryFunctions:testQuerySelectorAll() + local root = self.GUI.new({ + class = "container", + x = 0, + y = 0, + w = 500, + h = 500, + }) + + for i = 1, 3 do + self.GUI.new({ + class = "item", + parent = root, + x = i * 100, + y = 0, + w = 100, + h = 100, + }) + end + + -- Test querySelectorAll functionality + luaunit.assertNotNil(self.GUI.querySelectorAll) + local items = self.GUI:querySelectorAll(".item") + local containers = self.GUI:querySelectorAll(".container") + + luaunit.assertEquals(#items, 3) + luaunit.assertEquals(#containers, 1) +end + +function TestAuxiliaryFunctions:testDebugPrint() + local root = self.GUI.new({ + id = "root", + x = 0, + y = 0, + w = 500, + h = 500, + }) + + self.GUI.new({ + id = "child", + parent = root, + x = 0, + y = 0, + w = 100, + h = 100, + }) + + -- Test debug print functionality + luaunit.assertNotNil(self.GUI.debugPrint) + local debugOutput = self.GUI:debugPrint() + luaunit.assertNotNil(debugOutput) + luaunit.assertString(debugOutput) + luaunit.assertTrue(string.find(debugOutput, "root") ~= nil) + luaunit.assertTrue(string.find(debugOutput, "child") ~= nil) +end + +function TestAuxiliaryFunctions:testMeasureText() + local text = "Hello World" + local fontSize = 12 + + -- Test text measurement functionality + luaunit.assertNotNil(self.GUI.measureText) + local width, height = self.GUI:measureText(text, fontSize) + + luaunit.assertNotNil(width) + luaunit.assertNotNil(height) + luaunit.assertNumber(width) + luaunit.assertNumber(height) + luaunit.assertTrue(width > 0) + luaunit.assertTrue(height > 0) +end + +function TestAuxiliaryFunctions:testUtilityFunctions() + -- Test color conversion + luaunit.assertNotNil(self.GUI.hexToRGB) + local r, g, b = self.GUI:hexToRGB("#FF0000") + luaunit.assertEquals(r, 255) + luaunit.assertEquals(g, 0) + luaunit.assertEquals(b, 0) + + -- Test point inside rectangle + luaunit.assertNotNil(self.GUI.pointInRect) + local isInside = self.GUI:pointInRect(10, 10, 0, 0, 20, 20) + luaunit.assertTrue(isInside) + + -- Test rectangle intersection + luaunit.assertNotNil(self.GUI.rectIntersect) + local intersects = self.GUI:rectIntersect(0, 0, 10, 10, 5, 5, 10, 10) + luaunit.assertTrue(intersects) +end + +luaunit.LuaUnit.run() diff --git a/testing/__tests__/README.md b/testing/__tests__/README.md new file mode 100644 index 0000000..63199a6 --- /dev/null +++ b/testing/__tests__/README.md @@ -0,0 +1,135 @@ +# FlexLove GUI Library Test Suite + +This directory contains comprehensive tests for the FlexLove GUI library. The tests cover layout behavior, property management, animations, and utility functions. + +## Test Files + +1. **01_absolute_positioning.lua** + - Basic absolute positioning + - Parent-child relationships + - Coordinate system tests + +2. **02_flex_direction.lua** + - Horizontal flex layout + - Vertical flex layout + - Mixed direction layouts + +3. **03_vertical_flex_direction.lua** + - Vertical layout specifics + - Column-based layouts + - Vertical alignment + +4. **04_justify_content.lua** + - Flex-start alignment + - Flex-end alignment + - Space-between distribution + - Space-around distribution + +5. **05_align_items.lua** + - Cross-axis alignment + - Stretch behavior + - Baseline alignment + +6. **06_flex_wrap.lua** + - Wrapping behavior + - Multi-line layouts + - Wrap alignment + +7. **07_layout_validation.lua** + - Edge cases + - Nested containers + - Deep hierarchies + +8. **08_performance.lua** + - Large element counts + - Deep hierarchies + - Dynamic updates + - Rapid resizing + +9. **09_element_properties.lua** + - Basic properties + - Custom properties + - Property modification + - Visibility and clipping + +10. **10_animation_and_transform.lua** + - Basic transformations + - Animation tweening + - Easing functions + - Animation cancellation + +11. **11_auxiliary_functions.lua** + - Element queries + - Debug utilities + - Layout helpers + - Utility functions + +## Running Tests + +### Run All Tests +```bash +cd /path/to/station_alpha +for f in game/libs/testing/__tests__/flexlove/*.lua; do lua "$f"; done +``` + +### Run Specific Test File +```bash +cd /path/to/station_alpha +lua game/libs/testing/__tests__/flexlove/[test_file].lua +``` + +## Test Structure + +Each test file follows this general structure: + +```lua +package.path = package.path .. ";/path/to/station_alpha/?.lua" + +local luaunit = require('game/libs/testing/luaunit') +require('game/libs/testing/loveStub') +local FlexLove = require('game/libs/FlexLove') + +TestClassName = {} + +function TestClassName:setUp() + self.GUI = FlexLove.GUI +end + +function TestClassName:testFeature() + -- Test implementation +end + +os.exit(luaunit.LuaUnit.run()) +``` + +## Known Issues + +1. Layout Calculations + - Some justify-content calculations need verification + - Align-items behavior needs adjustment + - Flex-wrap positioning requires fixes + +2. Missing Methods + - Animation and transform methods not implemented + - Some utility functions not available + - Custom property support incomplete + +3. Performance + - Resize calculations may need optimization + - Deep hierarchy performance could be improved + +## Contributing + +When adding new tests: + +1. Follow the existing naming convention +2. Add proper type annotations +3. Include nil checks for optional features +4. Document expected behavior +5. Add the test to this README + +## Dependencies + +- Lua 5.1+ / LuaJIT +- LÖVE2D (for graphics features) +- luaunit (testing framework) \ No newline at end of file diff --git a/testing/runAll.lua b/testing/runAll.lua new file mode 100644 index 0000000..1ff6f78 --- /dev/null +++ b/testing/runAll.lua @@ -0,0 +1,42 @@ +package.path = package.path .. ";./?.lua;./game/?.lua;./game/utils/?.lua;./game/components/?.lua;./game/systems/?.lua" + +local luaunit = require("testing.luaunit") + +-- Run all tests in the __tests__ directory +local testFiles = { + "testing/__tests__/01_absolute_positioning.lua", + "testing/__tests__/02_flex_direction.lua", + "testing/__tests__/03_vertical_flex_direction.lua", + "testing/__tests__/04_justify_content.lua", + "testing/__tests__/05_align_items.lua", + "testing/__tests__/06_flex_wrap.lua", + "testing/__tests__/07_layout_validation.lua", + "testing/__tests__/08_performance.lua", + "testing/__tests__/09_element_properties.lua", + "testing/__tests__/10_animation_and_transform.lua", + "testing/__tests__/11_auxiliary_functions.lua", +} + +-- testingun all tests, but don't exit on error +local success = true +print("========================================") +print("Running ALL tests") +print("========================================") +for _, testFile in ipairs(testFiles) do + print("========================================") + print("Running test file: " .. testFile) + print("========================================") + local status, err = pcall(dofile, testFile) + if not status then + print("Error running test " .. testFile .. ": " .. tostring(err)) + success = false + end +end + +print("========================================") +print("All tests completed") +print("========================================") + +-- Run the tests and exit with appropriate code +local result = luaunit.LuaUnit.run() +os.exit(success and result or 1)