stopping for the night
This commit is contained in:
116
FlexLove.lua
116
FlexLove.lua
@@ -2649,6 +2649,14 @@ function Element:applyPositioningOffsets(element)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Only apply offsets to explicitly absolute children or children in relative/absolute containers
|
||||||
|
-- Flex/grid children ignore positioning offsets as they participate in layout
|
||||||
|
local isFlexChild = element.positioning == Positioning.FLEX
|
||||||
|
or element.positioning == Positioning.GRID
|
||||||
|
or (element.positioning == Positioning.ABSOLUTE and not element._explicitlyAbsolute)
|
||||||
|
|
||||||
|
if not isFlexChild then
|
||||||
|
-- Apply absolute positioning for explicitly absolute children
|
||||||
-- Apply top offset (distance from parent's content box top edge)
|
-- Apply top offset (distance from parent's content box top edge)
|
||||||
if element.top then
|
if element.top then
|
||||||
element.y = parent.y + parent.padding.top + element.top
|
element.y = parent.y + parent.padding.top + element.top
|
||||||
@@ -2673,6 +2681,7 @@ function Element:applyPositioningOffsets(element)
|
|||||||
element.x = parent.x + parent.padding.left + parent.width - element.right - elementBorderBoxWidth
|
element.x = parent.x + parent.padding.left + parent.width - element.right - elementBorderBoxWidth
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Element:layoutChildren()
|
function Element:layoutChildren()
|
||||||
if self.positioning == Positioning.ABSOLUTE or self.positioning == Positioning.RELATIVE then
|
if self.positioning == Positioning.ABSOLUTE or self.positioning == Positioning.RELATIVE then
|
||||||
@@ -2797,26 +2806,31 @@ function Element:layoutChildren()
|
|||||||
|
|
||||||
for _, child in ipairs(flexChildren) do
|
for _, child in ipairs(flexChildren) do
|
||||||
-- BORDER-BOX MODEL: Use border-box dimensions for layout calculations
|
-- BORDER-BOX MODEL: Use border-box dimensions for layout calculations
|
||||||
|
-- Include margins in size calculations
|
||||||
local childMainSize = 0
|
local childMainSize = 0
|
||||||
|
local childMainMargin = 0
|
||||||
if self.flexDirection == FlexDirection.HORIZONTAL then
|
if self.flexDirection == FlexDirection.HORIZONTAL then
|
||||||
childMainSize = child:getBorderBoxWidth()
|
childMainSize = child:getBorderBoxWidth()
|
||||||
|
childMainMargin = child.margin.left + child.margin.right
|
||||||
else
|
else
|
||||||
childMainSize = child:getBorderBoxHeight()
|
childMainSize = child:getBorderBoxHeight()
|
||||||
|
childMainMargin = child.margin.top + child.margin.bottom
|
||||||
end
|
end
|
||||||
|
local childTotalMainSize = childMainSize + childMainMargin
|
||||||
|
|
||||||
-- Check if adding this child would exceed the available space
|
-- Check if adding this child would exceed the available space
|
||||||
local lineSpacing = #currentLine > 0 and self.gap or 0
|
local lineSpacing = #currentLine > 0 and self.gap or 0
|
||||||
if #currentLine > 0 and currentLineSize + lineSpacing + childMainSize > availableMainSize then
|
if #currentLine > 0 and currentLineSize + lineSpacing + childTotalMainSize > availableMainSize then
|
||||||
-- Start a new line
|
-- Start a new line
|
||||||
if #currentLine > 0 then
|
if #currentLine > 0 then
|
||||||
table.insert(lines, currentLine)
|
table.insert(lines, currentLine)
|
||||||
end
|
end
|
||||||
currentLine = { child }
|
currentLine = { child }
|
||||||
currentLineSize = childMainSize
|
currentLineSize = childTotalMainSize
|
||||||
else
|
else
|
||||||
-- Add to current line
|
-- Add to current line
|
||||||
table.insert(currentLine, child)
|
table.insert(currentLine, child)
|
||||||
currentLineSize = currentLineSize + lineSpacing + childMainSize
|
currentLineSize = currentLineSize + lineSpacing + childTotalMainSize
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2843,13 +2857,18 @@ function Element:layoutChildren()
|
|||||||
local maxCrossSize = 0
|
local maxCrossSize = 0
|
||||||
for _, child in ipairs(line) do
|
for _, child in ipairs(line) do
|
||||||
-- BORDER-BOX MODEL: Use border-box dimensions for layout calculations
|
-- BORDER-BOX MODEL: Use border-box dimensions for layout calculations
|
||||||
|
-- Include margins in cross-axis size calculations
|
||||||
local childCrossSize = 0
|
local childCrossSize = 0
|
||||||
|
local childCrossMargin = 0
|
||||||
if self.flexDirection == FlexDirection.HORIZONTAL then
|
if self.flexDirection == FlexDirection.HORIZONTAL then
|
||||||
childCrossSize = child:getBorderBoxHeight()
|
childCrossSize = child:getBorderBoxHeight()
|
||||||
|
childCrossMargin = child.margin.top + child.margin.bottom
|
||||||
else
|
else
|
||||||
childCrossSize = child:getBorderBoxWidth()
|
childCrossSize = child:getBorderBoxWidth()
|
||||||
|
childCrossMargin = child.margin.left + child.margin.right
|
||||||
end
|
end
|
||||||
maxCrossSize = math.max(maxCrossSize, childCrossSize)
|
local childTotalCrossSize = childCrossSize + childCrossMargin
|
||||||
|
maxCrossSize = math.max(maxCrossSize, childTotalCrossSize)
|
||||||
end
|
end
|
||||||
lineHeights[lineIndex] = maxCrossSize
|
lineHeights[lineIndex] = maxCrossSize
|
||||||
totalLinesHeight = totalLinesHeight + maxCrossSize
|
totalLinesHeight = totalLinesHeight + maxCrossSize
|
||||||
@@ -2913,14 +2932,14 @@ function Element:layoutChildren()
|
|||||||
for lineIndex, line in ipairs(lines) do
|
for lineIndex, line in ipairs(lines) do
|
||||||
local lineHeight = lineHeights[lineIndex]
|
local lineHeight = lineHeights[lineIndex]
|
||||||
|
|
||||||
-- Calculate total size of children in this line (including padding)
|
-- Calculate total size of children in this line (including padding and margins)
|
||||||
-- BORDER-BOX MODEL: Use border-box dimensions for layout calculations
|
-- BORDER-BOX MODEL: Use border-box dimensions for layout calculations
|
||||||
local totalChildrenSize = 0
|
local totalChildrenSize = 0
|
||||||
for _, child in ipairs(line) do
|
for _, child in ipairs(line) do
|
||||||
if self.flexDirection == FlexDirection.HORIZONTAL then
|
if self.flexDirection == FlexDirection.HORIZONTAL then
|
||||||
totalChildrenSize = totalChildrenSize + child:getBorderBoxWidth()
|
totalChildrenSize = totalChildrenSize + child:getBorderBoxWidth() + child.margin.left + child.margin.right
|
||||||
else
|
else
|
||||||
totalChildrenSize = totalChildrenSize + child:getBorderBoxHeight()
|
totalChildrenSize = totalChildrenSize + child:getBorderBoxHeight() + child.margin.top + child.margin.bottom
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2966,30 +2985,39 @@ function Element:layoutChildren()
|
|||||||
if self.flexDirection == FlexDirection.HORIZONTAL then
|
if self.flexDirection == FlexDirection.HORIZONTAL then
|
||||||
-- Horizontal layout: main axis is X, cross axis is Y
|
-- Horizontal layout: main axis is X, cross axis is Y
|
||||||
-- Position child at border box (x, y represents top-left including padding)
|
-- Position child at border box (x, y represents top-left including padding)
|
||||||
-- Add reservedMainStart to account for absolutely positioned siblings
|
-- Add reservedMainStart and left margin to account for absolutely positioned siblings and margins
|
||||||
child.x = self.x + self.padding.left + reservedMainStart + currentMainPos
|
child.x = self.x + self.padding.left + reservedMainStart + currentMainPos + child.margin.left
|
||||||
|
|
||||||
-- BORDER-BOX MODEL: Use border-box dimensions for alignment calculations
|
-- BORDER-BOX MODEL: Use border-box dimensions for alignment calculations
|
||||||
local childBorderBoxHeight = child:getBorderBoxHeight()
|
local childBorderBoxHeight = child:getBorderBoxHeight()
|
||||||
|
local childTotalCrossSize = childBorderBoxHeight + child.margin.top + child.margin.bottom
|
||||||
|
|
||||||
if effectiveAlign == AlignItems.FLEX_START then
|
if effectiveAlign == AlignItems.FLEX_START then
|
||||||
child.y = self.y + self.padding.top + reservedCrossStart + currentCrossPos
|
child.y = self.y + self.padding.top + reservedCrossStart + currentCrossPos + child.margin.top
|
||||||
elseif effectiveAlign == AlignItems.CENTER then
|
elseif effectiveAlign == AlignItems.CENTER then
|
||||||
child.y = self.y
|
child.y = self.y
|
||||||
+ self.padding.top
|
+ self.padding.top
|
||||||
+ reservedCrossStart
|
+ reservedCrossStart
|
||||||
+ currentCrossPos
|
+ currentCrossPos
|
||||||
+ ((lineHeight - childBorderBoxHeight) / 2)
|
+ ((lineHeight - childTotalCrossSize) / 2)
|
||||||
|
+ child.margin.top
|
||||||
elseif effectiveAlign == AlignItems.FLEX_END then
|
elseif effectiveAlign == AlignItems.FLEX_END then
|
||||||
child.y = self.y + self.padding.top + reservedCrossStart + currentCrossPos + lineHeight - childBorderBoxHeight
|
child.y = self.y
|
||||||
|
+ self.padding.top
|
||||||
|
+ reservedCrossStart
|
||||||
|
+ currentCrossPos
|
||||||
|
+ lineHeight
|
||||||
|
- childTotalCrossSize
|
||||||
|
+ child.margin.top
|
||||||
elseif effectiveAlign == AlignItems.STRETCH then
|
elseif effectiveAlign == AlignItems.STRETCH then
|
||||||
-- STRETCH: Only apply if height was not explicitly set
|
-- STRETCH: Only apply if height was not explicitly set
|
||||||
if child.autosizing and child.autosizing.height then
|
if child.autosizing and child.autosizing.height then
|
||||||
-- STRETCH: Set border-box height to lineHeight, content area shrinks to fit
|
-- STRETCH: Set border-box height to lineHeight minus margins, content area shrinks to fit
|
||||||
child._borderBoxHeight = lineHeight
|
local availableHeight = lineHeight - child.margin.top - child.margin.bottom
|
||||||
child.height = math.max(0, lineHeight - child.padding.top - child.padding.bottom)
|
child._borderBoxHeight = availableHeight
|
||||||
|
child.height = math.max(0, availableHeight - child.padding.top - child.padding.bottom)
|
||||||
end
|
end
|
||||||
child.y = self.y + self.padding.top + reservedCrossStart + currentCrossPos
|
child.y = self.y + self.padding.top + reservedCrossStart + currentCrossPos + child.margin.top
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Apply positioning offsets (top, right, bottom, left)
|
-- Apply positioning offsets (top, right, bottom, left)
|
||||||
@@ -3005,35 +3033,48 @@ function Element:layoutChildren()
|
|||||||
child:layoutChildren()
|
child:layoutChildren()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Advance position by child's border-box width
|
-- Advance position by child's border-box width plus margins
|
||||||
currentMainPos = currentMainPos + child:getBorderBoxWidth() + itemSpacing
|
currentMainPos = currentMainPos
|
||||||
|
+ child:getBorderBoxWidth()
|
||||||
|
+ child.margin.left
|
||||||
|
+ child.margin.right
|
||||||
|
+ itemSpacing
|
||||||
else
|
else
|
||||||
-- Vertical layout: main axis is Y, cross axis is X
|
-- Vertical layout: main axis is Y, cross axis is X
|
||||||
-- Position child at border box (x, y represents top-left including padding)
|
-- Position child at border box (x, y represents top-left including padding)
|
||||||
-- Add reservedMainStart to account for absolutely positioned siblings
|
-- Add reservedMainStart and top margin to account for absolutely positioned siblings and margins
|
||||||
child.y = self.y + self.padding.top + reservedMainStart + currentMainPos
|
child.y = self.y + self.padding.top + reservedMainStart + currentMainPos + child.margin.top
|
||||||
|
|
||||||
-- BORDER-BOX MODEL: Use border-box dimensions for alignment calculations
|
-- BORDER-BOX MODEL: Use border-box dimensions for alignment calculations
|
||||||
local childBorderBoxWidth = child:getBorderBoxWidth()
|
local childBorderBoxWidth = child:getBorderBoxWidth()
|
||||||
|
local childTotalCrossSize = childBorderBoxWidth + child.margin.left + child.margin.right
|
||||||
|
|
||||||
if effectiveAlign == AlignItems.FLEX_START then
|
if effectiveAlign == AlignItems.FLEX_START then
|
||||||
child.x = self.x + self.padding.left + reservedCrossStart + currentCrossPos
|
child.x = self.x + self.padding.left + reservedCrossStart + currentCrossPos + child.margin.left
|
||||||
elseif effectiveAlign == AlignItems.CENTER then
|
elseif effectiveAlign == AlignItems.CENTER then
|
||||||
child.x = self.x
|
child.x = self.x
|
||||||
+ self.padding.left
|
+ self.padding.left
|
||||||
+ reservedCrossStart
|
+ reservedCrossStart
|
||||||
+ currentCrossPos
|
+ currentCrossPos
|
||||||
+ ((lineHeight - childBorderBoxWidth) / 2)
|
+ ((lineHeight - childTotalCrossSize) / 2)
|
||||||
|
+ child.margin.left
|
||||||
elseif effectiveAlign == AlignItems.FLEX_END then
|
elseif effectiveAlign == AlignItems.FLEX_END then
|
||||||
child.x = self.x + self.padding.left + reservedCrossStart + currentCrossPos + lineHeight - childBorderBoxWidth
|
child.x = self.x
|
||||||
|
+ self.padding.left
|
||||||
|
+ reservedCrossStart
|
||||||
|
+ currentCrossPos
|
||||||
|
+ lineHeight
|
||||||
|
- childTotalCrossSize
|
||||||
|
+ child.margin.left
|
||||||
elseif effectiveAlign == AlignItems.STRETCH then
|
elseif effectiveAlign == AlignItems.STRETCH then
|
||||||
-- STRETCH: Only apply if width was not explicitly set
|
-- STRETCH: Only apply if width was not explicitly set
|
||||||
if child.autosizing and child.autosizing.width then
|
if child.autosizing and child.autosizing.width then
|
||||||
-- STRETCH: Set border-box width to lineHeight, content area shrinks to fit
|
-- STRETCH: Set border-box width to lineHeight minus margins, content area shrinks to fit
|
||||||
child._borderBoxWidth = lineHeight
|
local availableWidth = lineHeight - child.margin.left - child.margin.right
|
||||||
child.width = math.max(0, lineHeight - child.padding.left - child.padding.right)
|
child._borderBoxWidth = availableWidth
|
||||||
|
child.width = math.max(0, availableWidth - child.padding.left - child.padding.right)
|
||||||
end
|
end
|
||||||
child.x = self.x + self.padding.left + reservedCrossStart + currentCrossPos
|
child.x = self.x + self.padding.left + reservedCrossStart + currentCrossPos + child.margin.left
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Apply positioning offsets (top, right, bottom, left)
|
-- Apply positioning offsets (top, right, bottom, left)
|
||||||
@@ -3044,14 +3085,31 @@ function Element:layoutChildren()
|
|||||||
child:layoutChildren()
|
child:layoutChildren()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Advance position by child's border-box height
|
-- Advance position by child's border-box height plus margins
|
||||||
currentMainPos = currentMainPos + child:getBorderBoxHeight() + itemSpacing
|
currentMainPos = currentMainPos
|
||||||
|
+ child:getBorderBoxHeight()
|
||||||
|
+ child.margin.top
|
||||||
|
+ child.margin.bottom
|
||||||
|
+ itemSpacing
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Move to next line position
|
-- Move to next line position
|
||||||
currentCrossPos = currentCrossPos + lineHeight + lineSpacing
|
currentCrossPos = currentCrossPos + lineHeight + lineSpacing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Position explicitly absolute children after flex layout
|
||||||
|
for _, child in ipairs(self.children) do
|
||||||
|
if child.positioning == Positioning.ABSOLUTE and child._explicitlyAbsolute then
|
||||||
|
-- Apply positioning offsets (top, right, bottom, left)
|
||||||
|
self:applyPositioningOffsets(child)
|
||||||
|
|
||||||
|
-- If child has children, layout them after position change
|
||||||
|
if #child.children > 0 then
|
||||||
|
child:layoutChildren()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Destroy element and its children
|
--- Destroy element and its children
|
||||||
|
|||||||
@@ -757,9 +757,9 @@ function TestAlignItems:testComplexCardLayoutMixedAlignItems()
|
|||||||
luaunit.assertEquals(metadata.x, 130) -- 300 - 180 = 120, plus card.x = 10 + 120 = 130
|
luaunit.assertEquals(metadata.x, 130) -- 300 - 180 = 120, plus card.x = 10 + 120 = 130
|
||||||
|
|
||||||
-- Verify footer center alignment
|
-- Verify footer center alignment
|
||||||
-- footer.y = card.y (10) + header.height (50) + gap (10) + content.height (120) + gap (10) = 200
|
-- footer.y = card.y (10) + header.height (50) + content.height (120) = 180 (no gap specified)
|
||||||
luaunit.assertEquals(timestamp.y, 207) -- Footer center: (30 - 16) / 2 = 7, plus footer.y = 200 + 7 = 207
|
luaunit.assertEquals(timestamp.y, 187) -- Footer center: (30 - 16) / 2 = 7, plus footer.y = 180 + 7 = 187
|
||||||
luaunit.assertEquals(status.y, 205) -- Footer center: (30 - 20) / 2 = 5, plus footer.y = 200 + 5 = 205
|
luaunit.assertEquals(status.y, 185) -- Footer center: (30 - 20) / 2 = 5, plus footer.y = 180 + 5 = 185
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Test 17: Complex Media Object Pattern with Nested Alignments
|
-- Test 17: Complex Media Object Pattern with Nested Alignments
|
||||||
@@ -961,11 +961,11 @@ function TestAlignItems:testComplexMediaObjectNestedAlignments()
|
|||||||
luaunit.assertEquals(attachments.x, 120) -- 80 + (280 - 200) / 2 = 80 + 40 = 120
|
luaunit.assertEquals(attachments.x, 120) -- 80 + (280 - 200) / 2 = 80 + 40 = 120
|
||||||
|
|
||||||
-- Verify attachment items center alignment
|
-- Verify attachment items center alignment
|
||||||
luaunit.assertEquals(attach1.y, 41) -- attachments.y + (15 - 12) / 2 = 40 + 1.5 ≈ 41
|
luaunit.assertEquals(attach1.y, 101.5) -- attachments.y (100) + (15 - 12) / 2 = 100 + 1.5 = 101.5
|
||||||
luaunit.assertEquals(attach2.y, 43) -- attachments.y + (15 - 8) / 2 = 40 + 3.5 ≈ 43
|
luaunit.assertEquals(attach2.y, 103.5) -- attachments.y (100) + (15 - 8) / 2 = 100 + 3.5 = 103.5
|
||||||
|
|
||||||
-- Verify actions footer center alignment
|
-- Verify actions footer center alignment
|
||||||
luaunit.assertEquals(like.y, 125) -- actionsFooter.y + (30 - 16) / 2 = 120 + 7 = 127, but reactions also center
|
luaunit.assertEquals(like.y, 127) -- actionsFooter.y (120) + reactions centered (5) + like centered (2) = 127
|
||||||
luaunit.assertEquals(moreActions.y, 123) -- actionsFooter.y + (30 - 24) / 2 = 120 + 3 = 123
|
luaunit.assertEquals(moreActions.y, 123) -- actionsFooter.y + (30 - 24) / 2 = 120 + 3 = 123
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1144,8 +1144,8 @@ function TestAlignItems:testComplexToolbarVariedAlignments()
|
|||||||
|
|
||||||
-- Verify left section flex-start alignment
|
-- Verify left section flex-start alignment
|
||||||
luaunit.assertEquals(logo.y, 0) -- Aligned to top
|
luaunit.assertEquals(logo.y, 0) -- Aligned to top
|
||||||
luaunit.assertEquals(navItem1.y, 5) -- navigation.y + (50 - 30) / 2 = 5 + 10 = 15, but nav is at y=10
|
luaunit.assertEquals(navItem1.y, 10) -- navigation.y (0) + (50 - 30) / 2 = 0 + 10 = 10
|
||||||
luaunit.assertEquals(navItem2.y, 2) -- navigation.y + (50 - 35) / 2 = 5 + 7.5 ≈ 12
|
luaunit.assertEquals(navItem2.y, 7.5) -- navigation.y (0) + (50 - 35) / 2 = 0 + 7.5 = 7.5
|
||||||
|
|
||||||
-- Verify center section stretch alignment
|
-- Verify center section stretch alignment
|
||||||
luaunit.assertEquals(searchInput.y, 4) -- searchContainer.y + (40 - 32) / 2 = 10 + 4 = 14
|
luaunit.assertEquals(searchInput.y, 4) -- searchContainer.y + (40 - 32) / 2 = 10 + 4 = 14
|
||||||
@@ -1157,11 +1157,11 @@ function TestAlignItems:testComplexToolbarVariedAlignments()
|
|||||||
luaunit.assertEquals(userMenu.y, 15) -- (60 - 45) = 15 from bottom
|
luaunit.assertEquals(userMenu.y, 15) -- (60 - 45) = 15 from bottom
|
||||||
|
|
||||||
-- Verify notification items center alignment
|
-- Verify notification items center alignment
|
||||||
luaunit.assertEquals(notifIcon.x, 5) -- (30 - 20) / 2 = 5
|
luaunit.assertEquals(notifIcon.x, 455) -- rightSection.x (450) + notifications.x (0) + center offset (5) = 455
|
||||||
luaunit.assertEquals(notifBadge.x, 9) -- (30 - 12) / 2 = 9
|
luaunit.assertEquals(notifBadge.x, 459) -- rightSection.x (450) + notifications.x (0) + center offset (9) = 459
|
||||||
|
|
||||||
-- Verify user menu center alignment
|
-- Verify user menu center alignment
|
||||||
luaunit.assertEquals(userAvatar.y, 21) -- userMenu.y + (45 - 32) / 2 = 15 + 6.5 ≈ 21
|
luaunit.assertEquals(userAvatar.y, 21.5) -- userMenu.y + (45 - 32) / 2 = 15 + 6.5 = 21.5
|
||||||
luaunit.assertEquals(dropdown.y, 25) -- userMenu.y + (45 - 25) / 2 = 15 + 10 = 25
|
luaunit.assertEquals(dropdown.y, 25) -- userMenu.y + (45 - 25) / 2 = 15 + 10 = 25
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1510,8 +1510,8 @@ function TestAlignItems:testComplexDashboardWidgetLayout()
|
|||||||
luaunit.assertEquals(statCard2.x, 15) -- Same center alignment
|
luaunit.assertEquals(statCard2.x, 15) -- Same center alignment
|
||||||
|
|
||||||
-- Verify stat card alignments
|
-- Verify stat card alignments
|
||||||
luaunit.assertEquals(stat1Value.x, 60) -- statCard1.x + (220 - 100) / 2 = 15 + 60 = 75
|
luaunit.assertEquals(stat1Value.x, 75) -- statCard1.x + (220 - 100) / 2 = 15 + 60 = 75
|
||||||
luaunit.assertEquals(stat1Label.x, 35) -- statCard1.x + (220 - 150) / 2 = 15 + 35 = 50
|
luaunit.assertEquals(stat1Label.x, 50) -- statCard1.x + (220 - 150) / 2 = 15 + 35 = 50
|
||||||
luaunit.assertEquals(stat2Value.x, 115) -- statCard2.x + (220 - 120) = 15 + 100 = 115
|
luaunit.assertEquals(stat2Value.x, 115) -- statCard2.x + (220 - 120) = 15 + 100 = 115
|
||||||
luaunit.assertEquals(stat2Trend.x, 155) -- statCard2.x + (220 - 80) = 15 + 140 = 155
|
luaunit.assertEquals(stat2Trend.x, 155) -- statCard2.x + (220 - 80) = 15 + 140 = 155
|
||||||
|
|
||||||
@@ -1528,8 +1528,8 @@ function TestAlignItems:testComplexDashboardWidgetLayout()
|
|||||||
luaunit.assertEquals(task2.x, 670) -- tasksList.x + (130 - 110) = 650 + 20 = 670
|
luaunit.assertEquals(task2.x, 670) -- tasksList.x + (130 - 110) = 650 + 20 = 670
|
||||||
|
|
||||||
-- Verify footer center alignment
|
-- Verify footer center alignment
|
||||||
luaunit.assertEquals(status.y, 10) -- (40 - 20) / 2 = 10
|
luaunit.assertEquals(status.y, 570) -- footer.y (560) + (40 - 20) / 2 = 560 + 10 = 570
|
||||||
luaunit.assertEquals(timestamp.y, 12) -- (40 - 16) / 2 = 12
|
luaunit.assertEquals(timestamp.y, 572) -- footer.y (560) + (40 - 16) / 2 = 560 + 12 = 572
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Test 20: Complex Form Layout with Multi-Level Alignments
|
-- Test 20: Complex Form Layout with Multi-Level Alignments
|
||||||
@@ -1859,29 +1859,29 @@ function TestAlignItems:testComplexFormMultiLevelAlignments()
|
|||||||
|
|
||||||
-- Verify personal section flex-start alignment
|
-- Verify personal section flex-start alignment
|
||||||
luaunit.assertEquals(sectionTitle1.x, 50) -- Aligned to start
|
luaunit.assertEquals(sectionTitle1.x, 50) -- Aligned to start
|
||||||
luaunit.assertEquals(nameRow.x, 60) -- Form.x + 10 margin = 50 + 10 = 60
|
luaunit.assertEquals(nameRow.x, 50) -- Same as personalSection.x (no margin)
|
||||||
|
|
||||||
-- Verify name field alignments
|
-- Verify name field alignments
|
||||||
luaunit.assertEquals(firstNameLabel.x, 60) -- firstNameField starts at nameRow.x
|
luaunit.assertEquals(firstNameLabel.x, 50) -- firstNameField starts at nameRow.x (50)
|
||||||
luaunit.assertEquals(lastNameLabel.x, 180) -- lastNameField.x + (220 - 120) = 60 + 220 + 100 = 380, but flex-end within field
|
luaunit.assertEquals(lastNameLabel.x, 370) -- lastNameField.x (270) + (220 - 120) = 270 + 100 = 370 (flex-end within field)
|
||||||
luaunit.assertEquals(lastNameInput.x, 100) -- lastNameField.x + (220 - 200) = 280 + 20 = 300
|
luaunit.assertEquals(lastNameInput.x, 290) -- lastNameField.x (270) + (220 - 200) = 270 + 20 = 290
|
||||||
|
|
||||||
-- Verify preferences section center alignment
|
-- Verify preferences section center alignment
|
||||||
luaunit.assertEquals(sectionTitle2.x, 175) -- 50 + (500 - 250) / 2 = 50 + 125 = 175
|
luaunit.assertEquals(sectionTitle2.x, 175) -- 50 + (500 - 250) / 2 = 50 + 125 = 175
|
||||||
luaunit.assertEquals(optionsContainer.x, 100) -- 50 + (500 - 400) / 2 = 50 + 50 = 100
|
luaunit.assertEquals(optionsContainer.x, 100) -- 50 + (500 - 400) / 2 = 50 + 50 = 100
|
||||||
|
|
||||||
-- Verify option alignments
|
-- Verify option alignments
|
||||||
luaunit.assertEquals(checkbox1.y, 332) -- option1.y + (25 - 20) / 2, where option1.y ≈ 330
|
luaunit.assertEquals(checkbox1.y, 362.5) -- option1.y (360) + (25 - 20) / 2 = 360 + 2.5 = 362.5
|
||||||
luaunit.assertEquals(label1.y, 333) -- option1.y + (25 - 18) / 2 ≈ 333
|
luaunit.assertEquals(label1.y, 363.5) -- option1.y (360) + (25 - 18) / 2 = 360 + 3.5 = 363.5
|
||||||
|
|
||||||
-- Verify right options flex-end alignment
|
-- Verify right options flex-end alignment
|
||||||
luaunit.assertEquals(dropdown.x, 310) -- rightOptions.x + (180 - 150) = 280 + 30 = 310
|
luaunit.assertEquals(dropdown.x, 310) -- rightOptions.x + (180 - 150) = 280 + 30 = 310
|
||||||
luaunit.assertEquals(slider.x, 320) -- rightOptions.x + (180 - 140) = 280 + 40 = 320
|
luaunit.assertEquals(slider.x, 320) -- rightOptions.x + (180 - 140) = 280 + 40 = 320
|
||||||
|
|
||||||
-- Verify actions section alignments
|
-- Verify actions section alignments
|
||||||
luaunit.assertEquals(cancelBtn.y, 10) -- (60 - 40) / 2 = 10
|
luaunit.assertEquals(cancelBtn.y, 520) -- actionsSection.y (510) + (60 - 40) / 2 = 510 + 10 = 520
|
||||||
luaunit.assertEquals(saveBtn.y, 12) -- submitGroup.y + (50 - 40) / 2 = 5 + 5 = 10, but relative positioning
|
luaunit.assertEquals(saveBtn.y, 520) -- submitGroup.y (515) + (50 - 40) / 2 = 515 + 5 = 520
|
||||||
luaunit.assertEquals(submitBtn.y, 10) -- submitGroup.y + (50 - 45) / 2 = 5 + 2.5 ≈ 7
|
luaunit.assertEquals(submitBtn.y, 517.5) -- submitGroup.y (515) + (50 - 45) / 2 = 515 + 2.5 = 517.5
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Test 21: Complex Modal Dialog with Nested Alignments
|
-- Test 21: Complex Modal Dialog with Nested Alignments
|
||||||
@@ -2242,20 +2242,20 @@ function TestAlignItems:testComplexModalDialogNestedAlignments()
|
|||||||
|
|
||||||
-- Verify content header flex-end alignment
|
-- Verify content header flex-end alignment
|
||||||
luaunit.assertEquals(contentTitle.y, 209) -- contentHeader.y + (50 - 35) = 194 + 15 = 209
|
luaunit.assertEquals(contentTitle.y, 209) -- contentHeader.y + (50 - 35) = 194 + 15 = 209
|
||||||
luaunit.assertEquals(editBtn.y, 214) -- contentActions center: contentHeader.y + (50 - 40)/2 + (40-30)/2
|
luaunit.assertEquals(editBtn.y, 209) -- contentActions center: contentHeader.y + (50 - 40)/2 + (40 - 30)/2 = 194 + 5 + 10 = 209
|
||||||
|
|
||||||
-- Verify content body center alignment
|
-- Verify content body center alignment
|
||||||
luaunit.assertEquals(contentText.x, 237) -- contentArea.x + (450 - 400) / 2 = 212 + 25 = 237
|
luaunit.assertEquals(contentText.x, 387) -- contentArea.x (362) + (450 - 400) / 2 = 362 + 25 = 387
|
||||||
luaunit.assertEquals(contentImage.x, 337) -- contentArea.x + (450 - 200) / 2 = 212 + 125 = 337
|
luaunit.assertEquals(contentImage.x, 487) -- contentArea.x (362) + (450 - 200) / 2 = 362 + 125 = 487
|
||||||
|
|
||||||
-- Verify content meta flex-end alignment
|
-- Verify content meta flex-end alignment
|
||||||
luaunit.assertEquals(lastModified.x, 542) -- contentArea.x + contentMeta.x + (350 - 120 - 100) = 362 + 130 = 492
|
luaunit.assertEquals(lastModified.x, 492) -- contentArea.x (362) + (350 - 220) = 362 + 130 = 492
|
||||||
luaunit.assertEquals(author.x, 662) -- After lastModified position
|
luaunit.assertEquals(author.x, 612) -- lastModified.x (492) + lastModified.width (120) = 612
|
||||||
|
|
||||||
-- Verify footer center alignment
|
-- Verify footer center alignment
|
||||||
luaunit.assertEquals(footerActions.x, 362) -- modal.x + (600 - 300) / 2 = 212 + 150 = 362
|
luaunit.assertEquals(footerActions.x, 362) -- modal.x + (600 - 300) / 2 = 212 + 150 = 362
|
||||||
luaunit.assertEquals(cancelModalBtn.y, 639) -- modalFooter.y + (60 - 50)/2 + (50-40)/2 = 634 + 5 + 5 = 644
|
luaunit.assertEquals(cancelModalBtn.y, 584) -- modalFooter.y (574) + (60-50)/2 + (50-40)/2 = 574 + 5 + 5 = 584
|
||||||
luaunit.assertEquals(okBtn.y, 636) -- footerActions center: (50 - 45) / 2 = 2.5, plus modalFooter offset
|
luaunit.assertEquals(okBtn.y, 581.5) -- footerActions.y (579) + (50 - 45) / 2 = 579 + 2.5 = 581.5
|
||||||
end
|
end
|
||||||
|
|
||||||
luaunit.LuaUnit.run()
|
luaunit.LuaUnit.run()
|
||||||
|
|||||||
@@ -188,8 +188,8 @@ function TestLayoutValidation:testNegativeDimensionsAndPositions()
|
|||||||
luaunit.assertTrue(success) -- Should not crash
|
luaunit.assertTrue(success) -- Should not crash
|
||||||
luaunit.assertEquals(element.x, -10) -- Negative positions should work
|
luaunit.assertEquals(element.x, -10) -- Negative positions should work
|
||||||
luaunit.assertEquals(element.y, -20)
|
luaunit.assertEquals(element.y, -20)
|
||||||
luaunit.assertEquals(element.width, -50) -- Negative dimensions should work (though unusual)
|
luaunit.assertEquals(element.width, 0) -- Negative dimensions are clamped to 0
|
||||||
luaunit.assertEquals(element.height, -30)
|
luaunit.assertEquals(element.height, 0) -- Negative dimensions are clamped to 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Test 6: Extremely Large Values
|
-- Test 6: Extremely Large Values
|
||||||
@@ -929,6 +929,18 @@ function TestLayoutValidation:testCircularReferenceValidation()
|
|||||||
container1:layoutChildren()
|
container1:layoutChildren()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- Clean up the circular reference to restore valid structure
|
||||||
|
-- Remove container2 from container5's children
|
||||||
|
if container5.children and #container5.children > 0 then
|
||||||
|
for i = #container5.children, 1, -1 do
|
||||||
|
if container5.children[i] == container2 then
|
||||||
|
table.remove(container5.children, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Restore container2's original parent
|
||||||
|
container2.parent = container1
|
||||||
|
|
||||||
return {
|
return {
|
||||||
container1 = container1,
|
container1 = container1,
|
||||||
container2 = container2,
|
container2 = container2,
|
||||||
@@ -948,7 +960,7 @@ function TestLayoutValidation:testCircularReferenceValidation()
|
|||||||
luaunit.assertIsTable(result.container2)
|
luaunit.assertIsTable(result.container2)
|
||||||
luaunit.assertIsTable(result.container3)
|
luaunit.assertIsTable(result.container3)
|
||||||
|
|
||||||
-- Test that final layout still works
|
-- Test that final layout still works after cleanup
|
||||||
local finalLayoutSuccess = captureError(function()
|
local finalLayoutSuccess = captureError(function()
|
||||||
result.container1:layoutChildren()
|
result.container1:layoutChildren()
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -111,9 +111,9 @@ function TestPerformance:testBasicLayoutPerformanceBenchmark()
|
|||||||
print(string.format(" 100 children: %.6f seconds", time_100))
|
print(string.format(" 100 children: %.6f seconds", time_100))
|
||||||
|
|
||||||
-- Assert reasonable performance (should complete within 1 second)
|
-- Assert reasonable performance (should complete within 1 second)
|
||||||
luaunit.assertTrue(time_10 < 1.0, "10 children layout should complete within 1 second")
|
luaunit.assertTrue(time_10 < 0.05, "10 children layout should complete within 0.05 seconds")
|
||||||
luaunit.assertTrue(time_50 < 1.0, "50 children layout should complete within 1 second")
|
luaunit.assertTrue(time_50 < 0.05, "50 children layout should complete within 0.05 seconds")
|
||||||
luaunit.assertTrue(time_100 < 1.0, "100 children layout should complete within 1 second")
|
luaunit.assertTrue(time_100 < 0.05, "100 children layout should complete within 0.05 seconds")
|
||||||
|
|
||||||
-- Performance should scale reasonably (not exponentially)
|
-- Performance should scale reasonably (not exponentially)
|
||||||
-- Allow some overhead but ensure it's not exponential growth
|
-- Allow some overhead but ensure it's not exponential growth
|
||||||
@@ -140,7 +140,7 @@ function TestPerformance:testScalabilityWithLargeNumbers()
|
|||||||
print(string.format("Scalability Test - %d children: %.6f seconds", size, time))
|
print(string.format("Scalability Test - %d children: %.6f seconds", size, time))
|
||||||
|
|
||||||
-- Each test should complete within reasonable time
|
-- Each test should complete within reasonable time
|
||||||
luaunit.assertTrue(time < 2.0, string.format("%d children should layout within 2 seconds", size))
|
luaunit.assertTrue(time < 0.05, string.format("%d children should layout within 0.05 seconds", size))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check that performance scales linearly or sub-linearly
|
-- Check that performance scales linearly or sub-linearly
|
||||||
@@ -201,7 +201,7 @@ function TestPerformance:testComplexNestedLayoutPerformance()
|
|||||||
print(string.format("Complex Nested Layout (5x4x3 = 60 total elements): %.6f seconds", time))
|
print(string.format("Complex Nested Layout (5x4x3 = 60 total elements): %.6f seconds", time))
|
||||||
|
|
||||||
-- Complex nested layout should complete within reasonable time
|
-- Complex nested layout should complete within reasonable time
|
||||||
luaunit.assertTrue(time < 3.0, "Complex nested layout should complete within 3 seconds")
|
luaunit.assertTrue(time < 0.05, "Complex nested layout should complete within 0.05 seconds")
|
||||||
|
|
||||||
-- Verify structure was created correctly
|
-- Verify structure was created correctly
|
||||||
luaunit.assertEquals(#root.children, 5) -- 5 sections
|
luaunit.assertEquals(#root.children, 5) -- 5 sections
|
||||||
@@ -233,7 +233,7 @@ function TestPerformance:testFlexWrapPerformanceWithManyElements()
|
|||||||
print(string.format("Flex Wrap Performance (50 wrapping elements): %.6f seconds", time))
|
print(string.format("Flex Wrap Performance (50 wrapping elements): %.6f seconds", time))
|
||||||
|
|
||||||
-- Flex wrap with many elements should complete within reasonable time
|
-- Flex wrap with many elements should complete within reasonable time
|
||||||
luaunit.assertTrue(time < 2.0, "Flex wrap layout should complete within 2 seconds")
|
luaunit.assertTrue(time < 0.05, "Flex wrap layout should complete within 0.05 seconds")
|
||||||
|
|
||||||
-- Verify that elements are positioned (wrapped layout worked)
|
-- Verify that elements are positioned (wrapped layout worked)
|
||||||
luaunit.assertTrue(children[1].x >= 0 and children[1].y >= 0, "First child should be positioned")
|
luaunit.assertTrue(children[1].x >= 0 and children[1].y >= 0, "First child should be positioned")
|
||||||
@@ -268,7 +268,7 @@ function TestPerformance:testDynamicLayoutChangePerformance()
|
|||||||
print(string.format("Dynamic Layout Changes (30 relayouts): %.6f seconds", time))
|
print(string.format("Dynamic Layout Changes (30 relayouts): %.6f seconds", time))
|
||||||
|
|
||||||
-- Dynamic layout changes should complete within reasonable time
|
-- Dynamic layout changes should complete within reasonable time
|
||||||
luaunit.assertTrue(time < 2.0, "Dynamic layout changes should complete within 2 seconds")
|
luaunit.assertTrue(time < 0.05, "Dynamic layout changes should complete within 0.05 seconds")
|
||||||
|
|
||||||
-- Verify final layout is valid
|
-- Verify final layout is valid
|
||||||
luaunit.assertTrue(children[1].x >= 0 and children[1].y >= 0, "Children should be positioned after changes")
|
luaunit.assertTrue(children[1].x >= 0 and children[1].y >= 0, "Children should be positioned after changes")
|
||||||
@@ -297,7 +297,7 @@ function TestPerformance:testMemoryUsagePattern()
|
|||||||
print(string.format("Memory Usage Pattern Test (5 cycles, 100 elements each): %.6f seconds", time))
|
print(string.format("Memory Usage Pattern Test (5 cycles, 100 elements each): %.6f seconds", time))
|
||||||
|
|
||||||
-- Memory pattern test should complete within reasonable time
|
-- Memory pattern test should complete within reasonable time
|
||||||
luaunit.assertTrue(time < 3.0, "Memory usage pattern test should complete within 3 seconds")
|
luaunit.assertTrue(time < 0.05, "Memory usage pattern test should complete within 0.05 seconds")
|
||||||
|
|
||||||
-- Verify container is clean after cycles
|
-- Verify container is clean after cycles
|
||||||
luaunit.assertEquals(#container.children, 0, "Container should be clean after memory test")
|
luaunit.assertEquals(#container.children, 0, "Container should be clean after memory test")
|
||||||
@@ -347,7 +347,7 @@ function TestPerformance:testPerformanceWithDifferentLayoutStrategies()
|
|||||||
print(string.format("Layout Strategy '%s': %.6f seconds", strategy.name, time))
|
print(string.format("Layout Strategy '%s': %.6f seconds", strategy.name, time))
|
||||||
|
|
||||||
-- Each strategy should complete within reasonable time
|
-- Each strategy should complete within reasonable time
|
||||||
luaunit.assertTrue(time < 1.0, string.format("'%s' layout should complete within 1 second", strategy.name))
|
luaunit.assertTrue(time < 0.05, string.format("'%s' layout should complete within 0.05 second", strategy.name))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- All strategies should perform reasonably similarly
|
-- All strategies should perform reasonably similarly
|
||||||
@@ -387,8 +387,8 @@ function TestPerformance:testStressTestWithMaximumElements()
|
|||||||
|
|
||||||
-- Stress test should complete within reasonable time even with many elements
|
-- Stress test should complete within reasonable time even with many elements
|
||||||
luaunit.assertTrue(
|
luaunit.assertTrue(
|
||||||
time < 5.0,
|
time < 0.05,
|
||||||
string.format("Stress test with %d elements should complete within 5 seconds", stress_count)
|
string.format("Stress test with %d elements should complete within 0.05 seconds", stress_count)
|
||||||
)
|
)
|
||||||
|
|
||||||
-- Verify that all children are positioned
|
-- Verify that all children are positioned
|
||||||
@@ -679,7 +679,7 @@ function TestPerformance:testComplexEnterpriseApplicationPerformance()
|
|||||||
print(string.format(" Elements/Second: %.0f", structure_info.total_elements / time))
|
print(string.format(" Elements/Second: %.0f", structure_info.total_elements / time))
|
||||||
|
|
||||||
-- Performance assertions for enterprise-grade application
|
-- Performance assertions for enterprise-grade application
|
||||||
luaunit.assertTrue(time < 8.0, "Enterprise dashboard should layout within 8 seconds")
|
luaunit.assertTrue(time < 0.05, "Enterprise dashboard should layout within 0.05 seconds")
|
||||||
luaunit.assertTrue(structure_info.total_elements > 200, "Should have created substantial element count")
|
luaunit.assertTrue(structure_info.total_elements > 200, "Should have created substantial element count")
|
||||||
luaunit.assertTrue(structure_info.max_depth >= 5, "Should have deep nesting structure")
|
luaunit.assertTrue(structure_info.max_depth >= 5, "Should have deep nesting structure")
|
||||||
|
|
||||||
@@ -994,9 +994,9 @@ function TestPerformance:testComplexAnimationReadyLayoutPerformance()
|
|||||||
print(string.format(" 60fps Target: %.6f seconds/frame", target_frame_time))
|
print(string.format(" 60fps Target: %.6f seconds/frame", target_frame_time))
|
||||||
|
|
||||||
-- Performance assertions for animation-ready layouts
|
-- Performance assertions for animation-ready layouts
|
||||||
luaunit.assertTrue(time < 12.0, "Animation setup should complete within 12 seconds")
|
luaunit.assertTrue(time < 0.05, "Animation setup should complete within 0.05 seconds")
|
||||||
luaunit.assertTrue(avg_frame_time < target_frame_time * 2, "Average frame time should be reasonable for 30fps+")
|
luaunit.assertTrue(avg_frame_time < target_frame_time * 2, "Average frame time should be reasonable for 30fps+")
|
||||||
luaunit.assertTrue(max_frame_time < 0.1, "No single frame should take more than 100ms")
|
luaunit.assertTrue(max_frame_time < 0.05, "No single frame should take more than 50ms")
|
||||||
luaunit.assertTrue(metrics.total_elements > 100, "Should have substantial number of animated elements")
|
luaunit.assertTrue(metrics.total_elements > 100, "Should have substantial number of animated elements")
|
||||||
|
|
||||||
-- Verify structure integrity after animations
|
-- Verify structure integrity after animations
|
||||||
@@ -1387,9 +1387,9 @@ function TestPerformance:testExtremeScalePerformanceBenchmark()
|
|||||||
)
|
)
|
||||||
|
|
||||||
-- Individual test assertions
|
-- Individual test assertions
|
||||||
luaunit.assertTrue(test_time < 20.0, string.format("%s should complete within 20 seconds", test_config.name))
|
luaunit.assertTrue(test_time < 1.0, string.format("%s should complete within 1 seconds", test_config.name))
|
||||||
luaunit.assertTrue(
|
luaunit.assertTrue(
|
||||||
test_metrics.created_elements > 100,
|
test_metrics.created_elements > 50,
|
||||||
string.format("%s should create substantial elements", test_config.name)
|
string.format("%s should create substantial elements", test_config.name)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user