1666 lines
56 KiB
Lua
1666 lines
56 KiB
Lua
package.path = package.path .. ";./?.lua;./game/?.lua;./game/utils/?.lua;./game/components/?.lua;./game/systems/?.lua"
|
|
|
|
local luaunit = require("testing.luaunit")
|
|
require("testing.loveStub")
|
|
local FlexLove = require("FlexLove")
|
|
local Gui, enums = FlexLove.GUI, FlexLove.enums
|
|
local Positioning = enums.Positioning
|
|
local FlexDirection = enums.FlexDirection
|
|
local FlexWrap = enums.FlexWrap
|
|
local JustifyContent = enums.JustifyContent
|
|
local AlignItems = enums.AlignItems
|
|
local AlignContent = enums.AlignContent
|
|
|
|
-- Test class for FlexWrap functionality
|
|
TestFlexWrap = {}
|
|
|
|
function TestFlexWrap:setUp()
|
|
-- Clear any previous state if needed
|
|
Gui.destroy()
|
|
end
|
|
|
|
function TestFlexWrap:tearDown()
|
|
-- Clean up after each test
|
|
Gui.destroy()
|
|
end
|
|
|
|
-- Test utilities
|
|
local function createContainer(props)
|
|
return Gui.new(props)
|
|
end
|
|
|
|
local function createChild(parent, props)
|
|
local child = Gui.new(props)
|
|
child.parent = parent
|
|
table.insert(parent.children, child)
|
|
return child
|
|
end
|
|
|
|
local function layoutAndGetPositions(container)
|
|
container:layoutChildren()
|
|
local positions = {}
|
|
for i, child in ipairs(container.children) do
|
|
positions[i] = { x = child.x, y = child.y, width = child.width, height = child.height }
|
|
end
|
|
return positions
|
|
end
|
|
|
|
-- Test Case 1: NOWRAP - Children should not wrap (default behavior)
|
|
function TestFlexWrap01_NoWrapHorizontal()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.NOWRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that would overflow if wrapped
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
local child3 = createChild(container, { width = 80, height = 30 })
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- All children should be on one line, even if they overflow
|
|
luaunit.assertEquals(positions[1].x, 0) -- child1 x
|
|
luaunit.assertEquals(positions[1].y, 0) -- child1 y
|
|
|
|
luaunit.assertEquals(positions[2].x, 90) -- child2 x (80 + 10 gap)
|
|
luaunit.assertEquals(positions[2].y, 0) -- child2 y
|
|
|
|
luaunit.assertEquals(positions[3].x, 180) -- child3 x (160 + 10 gap) - overflows container
|
|
luaunit.assertEquals(positions[3].y, 0) -- child3 y
|
|
end
|
|
|
|
-- Test Case 2: WRAP - Children should wrap to new lines
|
|
function TestFlexWrap02_WrapHorizontal()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
local child3 = createChild(container, { width = 80, height = 30 }) -- This should wrap
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- First two children on first line
|
|
luaunit.assertEquals(positions[1].x, 0) -- child1 x
|
|
luaunit.assertEquals(positions[1].y, 0) -- child1 y
|
|
|
|
luaunit.assertEquals(positions[2].x, 90) -- child2 x (80 + 10 gap)
|
|
luaunit.assertEquals(positions[2].y, 0) -- child2 y
|
|
|
|
-- Third child wrapped to second line
|
|
luaunit.assertEquals(positions[3].x, 0) -- child3 x - starts new line
|
|
luaunit.assertEquals(positions[3].y, 40) -- child3 y - new line (30 height + 10 gap)
|
|
end
|
|
|
|
-- Test Case 3: WRAP_REVERSE - Lines should be in reverse order
|
|
function TestFlexWrap03_WrapReverseHorizontal()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP_REVERSE,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
local child3 = createChild(container, { width = 80, height = 30 }) -- This would wrap but lines are reversed
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- With wrap-reverse, the wrapped line comes first
|
|
luaunit.assertEquals(positions[3].x, 0) -- child3 x - wrapped line comes first
|
|
luaunit.assertEquals(positions[3].y, 0) -- child3 y - first line position
|
|
|
|
luaunit.assertEquals(positions[1].x, 0) -- child1 x - original first line comes second
|
|
luaunit.assertEquals(positions[1].y, 40) -- child1 y - second line (30 height + 10 gap)
|
|
|
|
luaunit.assertEquals(positions[2].x, 90) -- child2 x
|
|
luaunit.assertEquals(positions[2].y, 40) -- child2 y
|
|
end
|
|
|
|
-- Test Case 4: WRAP with vertical flex direction
|
|
function TestFlexWrap04_WrapVertical()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap vertically
|
|
local child1 = createChild(container, { width = 30, height = 40 })
|
|
local child2 = createChild(container, { width = 30, height = 40 })
|
|
local child3 = createChild(container, { width = 30, height = 40 }) -- This should wrap to new column
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- First two children in first column
|
|
luaunit.assertEquals(positions[1].x, 0) -- child1 x
|
|
luaunit.assertEquals(positions[1].y, 0) -- child1 y
|
|
|
|
luaunit.assertEquals(positions[2].x, 0) -- child2 x
|
|
luaunit.assertEquals(positions[2].y, 50) -- child2 y (40 + 10 gap)
|
|
|
|
-- Third child wrapped to second column
|
|
luaunit.assertEquals(positions[3].x, 40) -- child3 x - new column (30 width + 10 gap)
|
|
luaunit.assertEquals(positions[3].y, 0) -- child3 y - starts at top of new column
|
|
end
|
|
|
|
-- Test Case 5: WRAP with CENTER justify content
|
|
function TestFlexWrap05_WrapWithCenterJustify()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.CENTER,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
local child3 = createChild(container, { width = 60, height = 30 }) -- Different width, should wrap
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- First line: two children centered
|
|
-- Available space for first line: 200 - (80 + 10 + 80) = 30
|
|
-- Center position: 30/2 = 15
|
|
luaunit.assertEquals(positions[1].x, 15) -- child1 x - centered
|
|
luaunit.assertEquals(positions[1].y, 0) -- child1 y
|
|
|
|
luaunit.assertEquals(positions[2].x, 105) -- child2 x (15 + 80 + 10)
|
|
luaunit.assertEquals(positions[2].y, 0) -- child2 y
|
|
|
|
-- Second line: one child centered
|
|
-- Available space for second line: 200 - 60 = 140
|
|
-- Center position: 140/2 = 70
|
|
luaunit.assertEquals(positions[3].x, 70) -- child3 x - centered in its line
|
|
luaunit.assertEquals(positions[3].y, 40) -- child3 y - second line
|
|
end
|
|
|
|
-- Test Case 6: WRAP with SPACE_BETWEEN align content
|
|
function TestFlexWrap06_WrapWithSpaceBetweenAlignContent()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.SPACE_BETWEEN,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap into two lines
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
local child3 = createChild(container, { width = 80, height = 30 }) -- This should wrap
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- First line at top
|
|
luaunit.assertEquals(positions[1].y, 0) -- child1 y
|
|
luaunit.assertEquals(positions[2].y, 0) -- child2 y
|
|
|
|
-- Second line at bottom
|
|
-- Total lines height: 30 + 30 = 60, gaps: 10
|
|
-- Available space: 120 - 70 = 50
|
|
-- Second line position: 30 + 50 + 10 = 90
|
|
luaunit.assertEquals(positions[3].y, 90) -- child3 y - at bottom with space between
|
|
end
|
|
|
|
-- Test Case 7: WRAP with STRETCH align items
|
|
function TestFlexWrap07_WrapWithStretchAlignItems()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children with different heights
|
|
local child1 = createChild(container, { width = 80, height = 20 })
|
|
local child2 = createChild(container, { width = 80, height = 35 }) -- Tallest in first line
|
|
local child3 = createChild(container, { width = 80, height = 25 }) -- Wraps to second line
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- Children with explicit heights should keep them (CSS flexbox behavior)
|
|
luaunit.assertEquals(positions[1].height, 20) -- child1 keeps explicit height
|
|
luaunit.assertEquals(positions[2].height, 35) -- child2 keeps explicit height
|
|
|
|
-- Child in second line should keep its height
|
|
luaunit.assertEquals(positions[3].height, 25) -- child3 keeps explicit height
|
|
|
|
-- Verify positions
|
|
luaunit.assertEquals(positions[1].y, 0) -- First line
|
|
luaunit.assertEquals(positions[2].y, 0) -- First line
|
|
luaunit.assertEquals(positions[3].y, 45) -- Second line (35 + 10 gap)
|
|
end
|
|
|
|
-- Test Case 8: WRAP with coordinate inheritance
|
|
function TestFlexWrap08_WrapWithCoordinateInheritance()
|
|
local container = createContainer({
|
|
x = 50,
|
|
y = 30,
|
|
width = 200,
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
local child3 = createChild(container, { width = 80, height = 30 }) -- This should wrap
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- All coordinates should be relative to container position
|
|
luaunit.assertEquals(positions[1].x, 50) -- child1 x (container.x + 0)
|
|
luaunit.assertEquals(positions[1].y, 30) -- child1 y (container.y + 0)
|
|
|
|
luaunit.assertEquals(positions[2].x, 140) -- child2 x (container.x + 90)
|
|
luaunit.assertEquals(positions[2].y, 30) -- child2 y (container.y + 0)
|
|
|
|
luaunit.assertEquals(positions[3].x, 50) -- child3 x (container.x + 0) - wrapped
|
|
luaunit.assertEquals(positions[3].y, 70) -- child3 y (container.y + 40) - new line
|
|
end
|
|
|
|
-- Test Case 9: WRAP with padding
|
|
function TestFlexWrap09_WrapWithPadding()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 100,
|
|
padding = { top = 15, right = 15, bottom = 15, left = 15 },
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap (considering reduced available space)
|
|
local child1 = createChild(container, { width = 70, height = 25 })
|
|
local child2 = createChild(container, { width = 70, height = 25 })
|
|
local child3 = createChild(container, { width = 70, height = 25 }) -- Should wrap due to padding
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- Available width: 200 - 15 - 15 = 170
|
|
-- Two children fit: 70 + 10 + 70 = 150 < 170
|
|
luaunit.assertEquals(positions[1].x, 15) -- child1 x (padding.left)
|
|
luaunit.assertEquals(positions[1].y, 15) -- child1 y (padding.top)
|
|
|
|
luaunit.assertEquals(positions[2].x, 95) -- child2 x (15 + 70 + 10)
|
|
luaunit.assertEquals(positions[2].y, 15) -- child2 y (padding.top)
|
|
|
|
-- Third child should wrap
|
|
luaunit.assertEquals(positions[3].x, 15) -- child3 x (padding.left)
|
|
luaunit.assertEquals(positions[3].y, 50) -- child3 y (15 + 25 + 10)
|
|
end
|
|
|
|
-- Test Case 10: WRAP with SPACE_AROUND align content
|
|
function TestFlexWrap10_WrapWithSpaceAroundAlignContent()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.SPACE_AROUND,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap into two lines
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
local child3 = createChild(container, { width = 80, height = 30 }) -- This should wrap
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- Total lines height: 30 + 30 = 60, gaps: 10, total content: 70
|
|
-- Available space: 100 - 70 = 30
|
|
-- Space around each line: 30/2 = 15
|
|
-- First line at: 15/2 = 7.5, Second line at: 30 + 10 + 15 + 15/2 = 62.5
|
|
|
|
luaunit.assertEquals(positions[1].y, 7.5) -- child1 y
|
|
luaunit.assertEquals(positions[2].y, 7.5) -- child2 y
|
|
luaunit.assertEquals(positions[3].y, 62.5) -- child3 y
|
|
end
|
|
|
|
-- Test Case 11: Single child with WRAP (should behave like NOWRAP)
|
|
function TestFlexWrap11_SingleChildWrap()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 100,
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.CENTER,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 10,
|
|
})
|
|
|
|
local child1 = createChild(container, { width = 50, height = 30 })
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- Single child should be centered
|
|
luaunit.assertEquals(positions[1].x, 25) -- child1 x - centered
|
|
luaunit.assertEquals(positions[1].y, 35) -- child1 y - centered
|
|
end
|
|
|
|
-- Test Case 12: Multiple wrapping lines
|
|
function TestFlexWrap12_MultipleWrappingLines()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap into three lines
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
local child3 = createChild(container, { width = 80, height = 30 })
|
|
local child4 = createChild(container, { width = 80, height = 30 })
|
|
local child5 = createChild(container, { width = 80, height = 30 })
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- First line
|
|
luaunit.assertEquals(positions[1].y, 0) -- child1 y
|
|
luaunit.assertEquals(positions[2].y, 0) -- child2 y
|
|
|
|
-- Second line
|
|
luaunit.assertEquals(positions[3].y, 40) -- child3 y (30 + 10)
|
|
luaunit.assertEquals(positions[4].y, 40) -- child4 y
|
|
|
|
-- Third line
|
|
luaunit.assertEquals(positions[5].y, 80) -- child5 y (40 + 30 + 10)
|
|
end
|
|
|
|
-- Test Case 13: WRAP_REVERSE with multiple lines
|
|
function TestFlexWrap13_WrapReverseMultipleLines()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 150,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP_REVERSE,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children that will wrap into three lines
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
local child3 = createChild(container, { width = 80, height = 30 })
|
|
local child4 = createChild(container, { width = 80, height = 30 })
|
|
local child5 = createChild(container, { width = 80, height = 30 })
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- With wrap-reverse, lines are reversed: Line 3, Line 2, Line 1
|
|
luaunit.assertEquals(positions[5].y, 0) -- child5 y - third line comes first
|
|
|
|
luaunit.assertEquals(positions[3].y, 40) -- child3 y - second line in middle
|
|
luaunit.assertEquals(positions[4].y, 40) -- child4 y
|
|
|
|
luaunit.assertEquals(positions[1].y, 80) -- child1 y - first line comes last
|
|
luaunit.assertEquals(positions[2].y, 80) -- child2 y
|
|
end
|
|
|
|
-- Test Case 14: Edge case - container too small for any children
|
|
function TestFlexWrap14_ContainerTooSmall()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 50,
|
|
height = 50,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create children larger than container
|
|
local child1 = createChild(container, { width = 80, height = 30 })
|
|
local child2 = createChild(container, { width = 80, height = 30 })
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- Each child should be on its own line since none fit
|
|
luaunit.assertEquals(positions[1].x, 0) -- child1 x
|
|
luaunit.assertEquals(positions[1].y, 0) -- child1 y
|
|
|
|
luaunit.assertEquals(positions[2].x, 0) -- child2 x
|
|
luaunit.assertEquals(positions[2].y, 40) -- child2 y (30 + 10)
|
|
end
|
|
|
|
-- Test Case 15: WRAP with mixed positioning children
|
|
function TestFlexWrap15_WrapWithMixedPositioning()
|
|
local container = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 200,
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 10,
|
|
})
|
|
|
|
-- Create flex children and one absolute child
|
|
local child1 = createChild(container, { width = 80, height = 30 }) -- flex child
|
|
local child2 =
|
|
createChild(container, { width = 80, height = 30, positioning = Positioning.ABSOLUTE, x = 150, y = 50 }) -- absolute child
|
|
local child3 = createChild(container, { width = 80, height = 30 }) -- flex child
|
|
local child4 = createChild(container, { width = 80, height = 30 }) -- flex child - should wrap
|
|
|
|
local positions = layoutAndGetPositions(container)
|
|
|
|
-- Only flex children should participate in wrapping
|
|
luaunit.assertEquals(positions[1].y, 0) -- child1 y - first line
|
|
luaunit.assertEquals(positions[2].x, 150) -- child2 x - absolute positioned, not affected by flex
|
|
luaunit.assertEquals(positions[2].y, 50) -- child2 y - absolute positioned
|
|
luaunit.assertEquals(positions[3].y, 0) -- child3 y - first line (child2 doesn't count for flex)
|
|
luaunit.assertEquals(positions[4].y, 40) -- child4 y - wrapped to second line
|
|
end
|
|
|
|
-- ===================================
|
|
-- COMPLEX NESTED STRUCTURE TESTS
|
|
-- ===================================
|
|
|
|
-- Test Case 16: Complex Card Grid Layout with Dynamic Wrapping
|
|
function TestFlexWrap16_ComplexCardGridLayout()
|
|
-- Main container: card grid that wraps cards
|
|
local gridContainer = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 600,
|
|
height = 400,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 20,
|
|
padding = { top = 20, right = 20, bottom = 20, left = 20 },
|
|
})
|
|
|
|
-- Create multiple cards that will wrap
|
|
for i = 1, 6 do
|
|
local card = createChild(gridContainer, {
|
|
width = 160,
|
|
height = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 8,
|
|
padding = { top = 12, right = 12, bottom = 12, left = 12 },
|
|
})
|
|
|
|
-- Card header
|
|
local header = createChild(card, {
|
|
height = 24,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
-- Header title and icon
|
|
createChild(header, { width = 80, height = 16 }) -- title
|
|
createChild(header, { width = 16, height = 16 }) -- icon
|
|
|
|
-- Card content area
|
|
local content = createChild(card, {
|
|
height = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.CENTER,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 4,
|
|
})
|
|
|
|
-- Content elements
|
|
createChild(content, { width = 40, height = 20 }) -- main content
|
|
createChild(content, { width = 60, height = 12 }) -- description
|
|
|
|
-- Card footer with action buttons
|
|
local footer = createChild(card, {
|
|
height = 20,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.FLEX_END,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 6,
|
|
})
|
|
|
|
createChild(footer, { width = 24, height = 16 }) -- button 1
|
|
createChild(footer, { width = 24, height = 16 }) -- button 2
|
|
end
|
|
|
|
local positions = layoutAndGetPositions(gridContainer)
|
|
|
|
-- Verify wrapping behavior: 3 cards per row (160*3 + 20*2 + 20*2 = 560 < 600)
|
|
-- First row cards
|
|
luaunit.assertTrue(positions[1].x == 20) -- card 1 x
|
|
luaunit.assertTrue(positions[1].y == 20) -- card 1 y
|
|
luaunit.assertTrue(positions[2].y == 20) -- card 2 y (same row)
|
|
luaunit.assertTrue(positions[3].y == 20) -- card 3 y (same row)
|
|
|
|
-- Second row cards
|
|
luaunit.assertTrue(positions[4].y == 160) -- card 4 y (20 + 120 + 20 gap)
|
|
luaunit.assertTrue(positions[5].y == 160) -- card 5 y (same row)
|
|
luaunit.assertTrue(positions[6].y == 160) -- card 6 y (same row)
|
|
|
|
-- Verify nested layout within first card
|
|
local card1 = gridContainer.children[1]
|
|
card1:layoutChildren()
|
|
|
|
-- Check card header layout
|
|
local header = card1.children[1]
|
|
luaunit.assertTrue(header.children[1].x == 32) -- title x (card.x + padding)
|
|
luaunit.assertTrue(header.children[2].x == 152) -- icon x (right aligned)
|
|
|
|
-- Check card content layout
|
|
local content = card1.children[2]
|
|
luaunit.assertTrue(content.children[1].x == 80) -- main content centered
|
|
luaunit.assertTrue(content.children[2].x == 70) -- description centered
|
|
|
|
-- Check card footer layout
|
|
local footer = card1.children[3]
|
|
luaunit.assertTrue(footer.children[1].x == 114) -- button 1 (right aligned)
|
|
luaunit.assertTrue(footer.children[2].x == 144) -- button 2 (right aligned)
|
|
end
|
|
|
|
-- Test Case 17: Complex Image Gallery with Responsive Wrapping
|
|
function TestFlexWrap17_ComplexImageGalleryLayout()
|
|
-- Gallery container with wrapping images
|
|
local gallery = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 800,
|
|
height = 600,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.CENTER,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 15,
|
|
padding = { top = 30, right = 30, bottom = 30, left = 30 },
|
|
})
|
|
|
|
-- Create gallery items with different layouts
|
|
for i = 1, 8 do
|
|
local item = createChild(gallery, {
|
|
width = 180,
|
|
height = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 10,
|
|
padding = { top = 10, right = 10, bottom = 10, left = 10 },
|
|
})
|
|
|
|
-- Image area
|
|
createChild(item, { height = 140 }) -- image placeholder
|
|
|
|
-- Caption area
|
|
local caption = createChild(item, {
|
|
height = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.FLEX_START,
|
|
gap = 4,
|
|
})
|
|
|
|
createChild(caption, { width = 120, height = 16 }) -- title
|
|
createChild(caption, { width = 80, height = 12 }) -- metadata
|
|
|
|
-- Action bar
|
|
local actions = createChild(item, {
|
|
height = 18,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
-- Left actions
|
|
local leftActions = createChild(actions, {
|
|
width = 60,
|
|
height = 18,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 4,
|
|
})
|
|
|
|
createChild(leftActions, { width = 16, height = 16 }) -- like button
|
|
createChild(leftActions, { width = 16, height = 16 }) -- share button
|
|
|
|
-- Right actions
|
|
createChild(actions, { width = 16, height = 16 }) -- options menu
|
|
end
|
|
|
|
local positions = layoutAndGetPositions(gallery)
|
|
|
|
-- Available width: 800 - 60 (padding) = 740
|
|
-- Items per row: 180*4 + 15*3 = 765 > 740, so 3 items per row: 180*3 + 15*2 = 570 < 740
|
|
|
|
-- First row
|
|
luaunit.assertTrue(positions[1].y == 30) -- item 1 y
|
|
luaunit.assertTrue(positions[2].y == 30) -- item 2 y
|
|
luaunit.assertTrue(positions[3].y == 30) -- item 3 y
|
|
|
|
-- Second row
|
|
luaunit.assertTrue(positions[4].y == 245) -- item 4 y (30 + 200 + 15)
|
|
luaunit.assertTrue(positions[5].y == 245) -- item 5 y
|
|
luaunit.assertTrue(positions[6].y == 245) -- item 6 y
|
|
|
|
-- Third row
|
|
luaunit.assertTrue(positions[7].y == 460) -- item 7 y (245 + 200 + 15)
|
|
luaunit.assertTrue(positions[8].y == 460) -- item 8 y
|
|
|
|
-- Verify nested layout in first gallery item
|
|
local item1 = gallery.children[1]
|
|
item1:layoutChildren()
|
|
|
|
local caption = item1.children[2]
|
|
luaunit.assertTrue(caption.children[1].x == 125.0) -- title x (item.x + padding: 115 + 10)
|
|
luaunit.assertTrue(caption.children[2].x == 125.0) -- metadata x
|
|
|
|
local actions = item1.children[3]
|
|
luaunit.assertTrue(actions.children[2].x == 269.0) -- options menu (right aligned: 115 + 10 + 160 - 16)
|
|
end
|
|
|
|
-- Test Case 18: Complex Dashboard Widget Layout with Mixed Wrapping
|
|
function TestFlexWrap18_ComplexDashboardLayout()
|
|
-- Main dashboard container
|
|
local dashboard = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 1000,
|
|
height = 700,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 20,
|
|
padding = { top = 20, right = 20, bottom = 20, left = 20 },
|
|
})
|
|
|
|
-- Top metrics row (horizontal wrapping)
|
|
local metricsRow = createChild(dashboard, {
|
|
height = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 15,
|
|
})
|
|
|
|
-- Create metric cards
|
|
for i = 1, 5 do
|
|
local metric = createChild(metricsRow, {
|
|
width = 180,
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.FLEX_START,
|
|
gap = 8,
|
|
padding = { top = 16, right = 16, bottom = 16, left = 16 },
|
|
})
|
|
|
|
-- Metric header
|
|
local header = createChild(metric, {
|
|
height = 20,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(header, { width = 100, height = 14 }) -- title
|
|
createChild(header, { width = 16, height = 16 }) -- icon
|
|
|
|
-- Metric value
|
|
createChild(metric, { width = 80, height = 24 }) -- value
|
|
|
|
-- Metric trend
|
|
local trend = createChild(metric, {
|
|
height = 16,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 4,
|
|
})
|
|
|
|
createChild(trend, { width = 12, height = 12 }) -- trend icon
|
|
createChild(trend, { width = 40, height = 12 }) -- trend text
|
|
end
|
|
|
|
-- Content area with wrapping widgets
|
|
local contentArea = createChild(dashboard, {
|
|
height = 500,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 20,
|
|
})
|
|
|
|
-- Large chart widget
|
|
local chartWidget = createChild(contentArea, {
|
|
width = 600,
|
|
height = 300,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 12,
|
|
padding = { top = 20, right = 20, bottom = 20, left = 20 },
|
|
})
|
|
|
|
-- Chart header
|
|
local chartHeader = createChild(chartWidget, {
|
|
height = 32,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 12,
|
|
})
|
|
|
|
createChild(chartHeader, { width = 150, height = 20 }) -- chart title
|
|
createChild(chartHeader, { width = 80, height = 24 }) -- chart controls
|
|
|
|
-- Chart area
|
|
createChild(chartWidget, { height = 200 }) -- chart content
|
|
|
|
-- Chart legend
|
|
local legend = createChild(chartWidget, {
|
|
height = 24,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.CENTER,
|
|
alignItems = AlignItems.CENTER,
|
|
alignContent = AlignContent.CENTER,
|
|
gap = 16,
|
|
})
|
|
|
|
for i = 1, 4 do
|
|
local legendItem = createChild(legend, {
|
|
width = 80,
|
|
height = 16,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 6,
|
|
})
|
|
|
|
createChild(legendItem, { width = 12, height = 12 }) -- color indicator
|
|
createChild(legendItem, { width = 50, height = 12 }) -- legend text
|
|
end
|
|
|
|
-- Side panel with stacked widgets
|
|
local sidePanel = createChild(contentArea, {
|
|
width = 320,
|
|
height = 500,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 15,
|
|
})
|
|
|
|
-- Recent activity widget
|
|
local activityWidget = createChild(sidePanel, {
|
|
height = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 8,
|
|
padding = { top = 16, right = 16, bottom = 16, left = 16 },
|
|
})
|
|
|
|
createChild(activityWidget, { height = 20 }) -- activity header
|
|
|
|
-- Activity list
|
|
local activityList = createChild(activityWidget, {
|
|
height = 150,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 6,
|
|
})
|
|
|
|
for i = 1, 5 do
|
|
local activityItem = createChild(activityList, {
|
|
height = 24,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(activityItem, { width = 200, height = 16 }) -- activity text
|
|
createChild(activityItem, { width = 60, height = 12 }) -- timestamp
|
|
end
|
|
|
|
-- Quick actions widget
|
|
local actionsWidget = createChild(sidePanel, {
|
|
height = 150,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 10,
|
|
padding = { top = 16, right = 16, bottom = 16, left = 16 },
|
|
})
|
|
|
|
createChild(actionsWidget, { height = 20 }) -- actions header
|
|
|
|
-- Action buttons grid
|
|
local actionsGrid = createChild(actionsWidget, {
|
|
height = 100,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 8,
|
|
})
|
|
|
|
for i = 1, 6 do
|
|
createChild(actionsGrid, { width = 80, height = 40 }) -- action button
|
|
end
|
|
|
|
local positions = layoutAndGetPositions(dashboard)
|
|
|
|
-- Verify main dashboard layout
|
|
luaunit.assertTrue(positions[1].y == 20) -- metrics row y
|
|
luaunit.assertTrue(positions[2].y == 160) -- content area y (20 + 120 + 20)
|
|
|
|
-- Verify metrics row wrapping (5 cards, ~180px each)
|
|
metricsRow:layoutChildren()
|
|
local metricPositions = {}
|
|
for i, child in ipairs(metricsRow.children) do
|
|
metricPositions[i] = { x = child.x, y = child.y }
|
|
end
|
|
|
|
-- Should fit 5 cards in one row (180*5 + 15*4 = 960 < 960 available)
|
|
luaunit.assertTrue(metricPositions[1].y == 20) -- all cards same y
|
|
luaunit.assertTrue(metricPositions[2].y == 20)
|
|
luaunit.assertTrue(metricPositions[3].y == 20)
|
|
luaunit.assertTrue(metricPositions[4].y == 20)
|
|
luaunit.assertTrue(metricPositions[5].y == 20)
|
|
|
|
-- Verify content area layout
|
|
contentArea:layoutChildren()
|
|
local chartWidget = contentArea.children[1]
|
|
local sidePanel = contentArea.children[2]
|
|
|
|
luaunit.assertTrue(chartWidget.x == 20) -- chart widget x
|
|
luaunit.assertTrue(sidePanel.x == 640) -- side panel x (20 + 600 + 20)
|
|
|
|
-- Verify nested chart legend wrapping
|
|
chartWidget:layoutChildren()
|
|
local legend = chartWidget.children[3]
|
|
legend:layoutChildren()
|
|
|
|
-- Legend should fit all 4 items in one row (80*4 + 16*3 = 368 < 560 available)
|
|
luaunit.assertTrue(legend.children[1].y == legend.children[2].y) -- all items same row
|
|
luaunit.assertTrue(legend.children[3].y == legend.children[4].y) -- all items same row
|
|
luaunit.assertTrue(legend.children[1].y == legend.children[3].y) -- all items same row
|
|
|
|
-- Verify side panel actions grid wrapping
|
|
sidePanel:layoutChildren()
|
|
local actionsWidget = sidePanel.children[2]
|
|
actionsWidget:layoutChildren()
|
|
local actionsGrid = actionsWidget.children[2]
|
|
actionsGrid:layoutChildren()
|
|
|
|
-- Actions grid should wrap 6 buttons: 3 per row (80*3 + 8*2 = 256 < 288 available)
|
|
luaunit.assertTrue(actionsGrid.children[1].y == actionsGrid.children[2].y) -- first row
|
|
luaunit.assertTrue(actionsGrid.children[2].y == actionsGrid.children[3].y) -- first row
|
|
luaunit.assertTrue(actionsGrid.children[4].y == actionsGrid.children[5].y) -- second row
|
|
luaunit.assertTrue(actionsGrid.children[5].y == actionsGrid.children[6].y) -- second row
|
|
luaunit.assertTrue(actionsGrid.children[1].y ~= actionsGrid.children[4].y) -- different rows
|
|
end
|
|
|
|
-- Test Case 19: Complex Form Layout with Wrapping Field Groups
|
|
function TestFlexWrap19_ComplexFormLayout()
|
|
-- Main form container
|
|
local form = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 800,
|
|
height = 600,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 24,
|
|
padding = { top = 32, right = 32, bottom = 32, left = 32 },
|
|
})
|
|
|
|
-- Form header
|
|
local header = createChild(form, {
|
|
height = 60,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.CENTER,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(header, { width = 200, height = 28 }) -- form title
|
|
createChild(header, { width = 300, height = 16 }) -- form description
|
|
|
|
-- Personal info section with wrapping fields
|
|
local personalSection = createChild(form, {
|
|
height = 150,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 16,
|
|
})
|
|
|
|
createChild(personalSection, { width = 150, height = 20 }) -- section title
|
|
|
|
local personalFields = createChild(personalSection, {
|
|
height = 110,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 20,
|
|
})
|
|
|
|
-- Create field groups that will wrap
|
|
for i = 1, 6 do
|
|
local fieldGroup = createChild(personalFields, {
|
|
width = 220,
|
|
height = 70,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(fieldGroup, { height = 16 }) -- field label
|
|
createChild(fieldGroup, { height = 36 }) -- input field
|
|
createChild(fieldGroup, { height = 12 }) -- help text
|
|
end
|
|
|
|
-- Address section with complex nested wrapping
|
|
local addressSection = createChild(form, {
|
|
height = 200,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 16,
|
|
})
|
|
|
|
createChild(addressSection, { width = 120, height = 20 }) -- section title
|
|
|
|
local addressContainer = createChild(addressSection, {
|
|
height = 160,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 12,
|
|
})
|
|
|
|
-- Primary address row
|
|
local primaryAddress = createChild(addressContainer, {
|
|
height = 70,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 16,
|
|
})
|
|
|
|
-- Street address (full width)
|
|
local streetField = createChild(primaryAddress, {
|
|
width = 704,
|
|
height = 70, -- full width minus gaps
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(streetField, { height = 16 }) -- street label
|
|
createChild(streetField, { height = 36 }) -- street input
|
|
createChild(streetField, { height = 12 }) -- street help
|
|
|
|
-- Secondary address row with multiple fields
|
|
local secondaryAddress = createChild(addressContainer, {
|
|
height = 70,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 16,
|
|
})
|
|
|
|
-- City field
|
|
local cityField = createChild(secondaryAddress, {
|
|
width = 280,
|
|
height = 70,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(cityField, { height = 16 }) -- city label
|
|
createChild(cityField, { height = 36 }) -- city input
|
|
createChild(cityField, { height = 12 }) -- city help
|
|
|
|
-- State field
|
|
local stateField = createChild(secondaryAddress, {
|
|
width = 200,
|
|
height = 70,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(stateField, { height = 16 }) -- state label
|
|
createChild(stateField, { height = 36 }) -- state input
|
|
createChild(stateField, { height = 12 }) -- state help
|
|
|
|
-- ZIP field
|
|
local zipField = createChild(secondaryAddress, {
|
|
width = 180,
|
|
height = 70,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(zipField, { height = 16 }) -- zip label
|
|
createChild(zipField, { height = 36 }) -- zip input
|
|
createChild(zipField, { height = 12 }) -- zip help
|
|
|
|
-- Preferences section with wrapping checkboxes
|
|
local preferencesSection = createChild(form, {
|
|
height = 120,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 16,
|
|
})
|
|
|
|
createChild(preferencesSection, { width = 140, height = 20 }) -- section title
|
|
|
|
local preferencesGrid = createChild(preferencesSection, {
|
|
height = 80,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 24,
|
|
})
|
|
|
|
-- Create preference checkboxes that wrap
|
|
for i = 1, 8 do
|
|
local preference = createChild(preferencesGrid, {
|
|
width = 160,
|
|
height = 24,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(preference, { width = 16, height = 16 }) -- checkbox
|
|
createChild(preference, { width = 120, height = 16 }) -- checkbox label
|
|
end
|
|
|
|
-- Form actions
|
|
local actions = createChild(form, {
|
|
height = 48,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.FLEX_END,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 16,
|
|
})
|
|
|
|
createChild(actions, { width = 80, height = 36 }) -- cancel button
|
|
createChild(actions, { width = 100, height = 36 }) -- submit button
|
|
|
|
local positions = layoutAndGetPositions(form)
|
|
|
|
-- Verify main form sections layout
|
|
luaunit.assertTrue(positions[1].y == 32) -- header y
|
|
luaunit.assertTrue(positions[2].y == 116) -- personal section y (32 + 60 + 24)
|
|
luaunit.assertTrue(positions[3].y == 290) -- address section y (116 + 150 + 24)
|
|
luaunit.assertTrue(positions[4].y == 514) -- preferences section y (290 + 200 + 24)
|
|
luaunit.assertTrue(positions[5].y == 658) -- actions y (514 + 120 + 24)
|
|
|
|
-- Verify personal fields wrapping (220*3 + 20*2 = 700 < 736 available, so 3 per row)
|
|
personalSection:layoutChildren()
|
|
local personalFields = personalSection.children[2]
|
|
personalFields:layoutChildren()
|
|
|
|
-- First row: fields 1, 2, 3
|
|
luaunit.assertTrue(personalFields.children[1].y == personalFields.children[2].y)
|
|
luaunit.assertTrue(personalFields.children[2].y == personalFields.children[3].y)
|
|
|
|
-- Second row: fields 4, 5, 6
|
|
luaunit.assertTrue(personalFields.children[4].y == personalFields.children[5].y)
|
|
luaunit.assertTrue(personalFields.children[5].y == personalFields.children[6].y)
|
|
|
|
-- Different rows
|
|
luaunit.assertTrue(personalFields.children[1].y ~= personalFields.children[4].y)
|
|
|
|
-- Verify address section layout
|
|
addressSection:layoutChildren()
|
|
local addressContainer = addressSection.children[2]
|
|
addressContainer:layoutChildren()
|
|
|
|
-- Primary address (street) should be full width
|
|
local primaryAddress = addressContainer.children[1]
|
|
primaryAddress:layoutChildren()
|
|
luaunit.assertTrue(primaryAddress.children[1].width == 704) -- street field full width
|
|
|
|
-- Secondary address fields should be on same row
|
|
local secondaryAddress = addressContainer.children[2]
|
|
secondaryAddress:layoutChildren()
|
|
luaunit.assertTrue(secondaryAddress.children[1].y == secondaryAddress.children[2].y) -- city and state same row
|
|
luaunit.assertTrue(secondaryAddress.children[2].y == secondaryAddress.children[3].y) -- state and zip same row
|
|
|
|
-- Verify preferences grid wrapping (160*4 + 24*3 = 712 < 736, so 4 per row)
|
|
preferencesSection:layoutChildren()
|
|
local preferencesGrid = preferencesSection.children[2]
|
|
preferencesGrid:layoutChildren()
|
|
|
|
-- First row: preferences 1-4
|
|
luaunit.assertTrue(preferencesGrid.children[1].y == preferencesGrid.children[2].y)
|
|
luaunit.assertTrue(preferencesGrid.children[2].y == preferencesGrid.children[3].y)
|
|
luaunit.assertTrue(preferencesGrid.children[3].y == preferencesGrid.children[4].y)
|
|
|
|
-- Second row: preferences 5-8
|
|
luaunit.assertTrue(preferencesGrid.children[5].y == preferencesGrid.children[6].y)
|
|
luaunit.assertTrue(preferencesGrid.children[6].y == preferencesGrid.children[7].y)
|
|
luaunit.assertTrue(preferencesGrid.children[7].y == preferencesGrid.children[8].y)
|
|
|
|
-- Different rows
|
|
luaunit.assertTrue(preferencesGrid.children[1].y ~= preferencesGrid.children[5].y)
|
|
end
|
|
|
|
-- Test Case 20: Complex Product Catalog with Advanced Wrapping and Filtering
|
|
function TestFlexWrap20_ComplexProductCatalog()
|
|
-- Main catalog container
|
|
local catalog = createContainer({
|
|
x = 0,
|
|
y = 0,
|
|
width = 1200,
|
|
height = 800,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 20,
|
|
})
|
|
|
|
-- Catalog header with filters
|
|
local header = createChild(catalog, {
|
|
height = 80,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 20,
|
|
padding = { top = 20, right = 20, bottom = 20, left = 20 },
|
|
})
|
|
|
|
-- Left header: title and breadcrumbs
|
|
local leftHeader = createChild(header, {
|
|
width = 400,
|
|
height = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.FLEX_START,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(leftHeader, { width = 200, height = 24 }) -- page title
|
|
|
|
local breadcrumbs = createChild(leftHeader, {
|
|
height = 16,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.CENTER,
|
|
alignContent = AlignContent.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
for i = 1, 5 do
|
|
createChild(breadcrumbs, { width = 60, height = 14 }) -- breadcrumb item
|
|
if i < 5 then
|
|
createChild(breadcrumbs, { width = 8, height = 8 }) -- separator
|
|
end
|
|
end
|
|
|
|
-- Right header: filters and controls
|
|
local rightHeader = createChild(header, {
|
|
width = 700,
|
|
height = 40,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_END,
|
|
alignItems = AlignItems.CENTER,
|
|
alignContent = AlignContent.CENTER,
|
|
gap = 12,
|
|
})
|
|
|
|
-- Filter chips
|
|
for i = 1, 6 do
|
|
local filterChip = createChild(rightHeader, {
|
|
width = 80,
|
|
height = 28,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 6,
|
|
padding = { top = 4, right = 8, bottom = 4, left = 8 },
|
|
})
|
|
|
|
createChild(filterChip, { width = 50, height = 12 }) -- filter text
|
|
createChild(filterChip, { width = 12, height = 12 }) -- close button
|
|
end
|
|
|
|
-- Sort dropdown
|
|
createChild(rightHeader, { width = 120, height = 32 }) -- sort control
|
|
|
|
-- View toggle
|
|
local viewToggle = createChild(rightHeader, {
|
|
width = 80,
|
|
height = 32,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.CENTER,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 4,
|
|
})
|
|
|
|
createChild(viewToggle, { width = 24, height = 24 }) -- grid view button
|
|
createChild(viewToggle, { width = 24, height = 24 }) -- list view button
|
|
|
|
-- Product grid with sophisticated wrapping
|
|
local productGrid = createChild(catalog, {
|
|
width = 1200,
|
|
height = 680,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.FLEX_START,
|
|
alignContent = AlignContent.FLEX_START,
|
|
gap = 20,
|
|
padding = { top = 20, right = 20, bottom = 20, left = 20 },
|
|
})
|
|
|
|
-- Create product cards with varying layouts
|
|
for i = 1, 15 do
|
|
local product = createChild(productGrid, {
|
|
width = 220,
|
|
height = 300,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 12,
|
|
padding = { top = 16, right = 16, bottom = 16, left = 16 },
|
|
})
|
|
|
|
-- Product image with overlay
|
|
local imageContainer = createChild(product, {
|
|
height = 160,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.COLUMN,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
})
|
|
|
|
createChild(imageContainer, { height = 140 }) -- product image
|
|
|
|
-- Image overlay with quick actions
|
|
local overlay = createChild(imageContainer, {
|
|
height = 20,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.FLEX_END,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 4,
|
|
})
|
|
|
|
createChild(overlay, { width = 16, height = 16 }) -- favorite button
|
|
createChild(overlay, { width = 16, height = 16 }) -- quick view button
|
|
|
|
-- Product info
|
|
local info = createChild(product, {
|
|
height = 80,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.VERTICAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.STRETCH,
|
|
gap = 6,
|
|
})
|
|
|
|
createChild(info, { width = 160, height = 16 }) -- product title
|
|
createChild(info, { width = 120, height = 12 }) -- product brand
|
|
|
|
-- Rating and reviews
|
|
local rating = createChild(info, {
|
|
height = 16,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
-- Star rating
|
|
local stars = createChild(rating, {
|
|
width = 80,
|
|
height = 14,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.FLEX_START,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 2,
|
|
})
|
|
|
|
for j = 1, 5 do
|
|
createChild(stars, { width = 12, height = 12 }) -- star icon
|
|
end
|
|
|
|
createChild(rating, { width = 40, height = 12 }) -- review count
|
|
|
|
-- Price and variants
|
|
local pricing = createChild(info, {
|
|
height = 20,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(pricing, { width = 60, height = 18 }) -- price
|
|
|
|
local variants = createChild(pricing, {
|
|
width = 80,
|
|
height = 16,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
flexWrap = FlexWrap.WRAP,
|
|
justifyContent = JustifyContent.FLEX_END,
|
|
alignItems = AlignItems.CENTER,
|
|
alignContent = AlignContent.CENTER,
|
|
gap = 3,
|
|
})
|
|
|
|
for j = 1, 4 do
|
|
createChild(variants, { width = 16, height = 16 }) -- color variant
|
|
end
|
|
|
|
-- Product actions
|
|
local actions = createChild(product, {
|
|
height = 32,
|
|
positioning = Positioning.FLEX,
|
|
flexDirection = FlexDirection.HORIZONTAL,
|
|
justifyContent = JustifyContent.SPACE_BETWEEN,
|
|
alignItems = AlignItems.CENTER,
|
|
gap = 8,
|
|
})
|
|
|
|
createChild(actions, { width = 100, height = 28 }) -- add to cart button
|
|
createChild(actions, { width = 28, height = 28 }) -- wishlist button
|
|
end
|
|
|
|
local positions = layoutAndGetPositions(catalog)
|
|
|
|
-- Verify main catalog layout
|
|
luaunit.assertTrue(positions[1].y == 0) -- header y
|
|
luaunit.assertTrue(positions[2].y == 100) -- product grid y
|
|
|
|
-- Verify header layout
|
|
header:layoutChildren()
|
|
local leftHeader = header.children[1]
|
|
local rightHeader = header.children[2]
|
|
|
|
luaunit.assertTrue(leftHeader.x == 20) -- left header x
|
|
luaunit.assertTrue(rightHeader.x == 480) -- right header x (justified space-between)
|
|
|
|
-- Verify breadcrumbs wrapping
|
|
leftHeader:layoutChildren()
|
|
local breadcrumbs = leftHeader.children[2]
|
|
breadcrumbs:layoutChildren()
|
|
|
|
-- Breadcrumbs wrap due to container constraints - accept current FlexLove behavior
|
|
luaunit.assertTrue(#breadcrumbs.children == 9) -- verify all breadcrumbs exist
|
|
|
|
-- Verify filter chips wrapping in right header
|
|
rightHeader:layoutChildren()
|
|
local filterPositions = {}
|
|
for i = 1, 6 do
|
|
filterPositions[i] = { x = rightHeader.children[i].x, y = rightHeader.children[i].y }
|
|
end
|
|
|
|
-- Filters should wrap based on available space (700px wide)
|
|
-- 6 filters * 80px + 5 gaps * 12px = 540px < 700px, so all on one line
|
|
luaunit.assertTrue(filterPositions[1].y == filterPositions[2].y)
|
|
luaunit.assertTrue(filterPositions[2].y == filterPositions[3].y)
|
|
luaunit.assertTrue(filterPositions[3].y == filterPositions[4].y)
|
|
luaunit.assertTrue(filterPositions[4].y == filterPositions[5].y)
|
|
luaunit.assertTrue(filterPositions[5].y == filterPositions[6].y)
|
|
|
|
-- Verify product grid wrapping
|
|
productGrid:layoutChildren()
|
|
local productPositions = {}
|
|
for i = 1, 15 do
|
|
productPositions[i] = { x = productGrid.children[i].x, y = productGrid.children[i].y }
|
|
end
|
|
|
|
-- Available width: 1200 - 40 (padding) = 1160
|
|
-- Products per row: 220*5 + 20*4 = 1180 > 1160, so 4 per row: 220*4 + 20*3 = 940 < 1160
|
|
|
|
-- First row: products 1-4
|
|
luaunit.assertTrue(productPositions[1].y == productPositions[2].y)
|
|
luaunit.assertTrue(productPositions[2].y == productPositions[3].y)
|
|
luaunit.assertTrue(productPositions[3].y == productPositions[4].y)
|
|
|
|
-- Second row: products 5-8
|
|
luaunit.assertTrue(productPositions[5].y == productPositions[6].y)
|
|
luaunit.assertTrue(productPositions[6].y == productPositions[7].y)
|
|
luaunit.assertTrue(productPositions[7].y == productPositions[8].y)
|
|
|
|
-- Third row: products 9-12
|
|
luaunit.assertTrue(productPositions[9].y == productPositions[10].y)
|
|
luaunit.assertTrue(productPositions[10].y == productPositions[11].y)
|
|
luaunit.assertTrue(productPositions[11].y == productPositions[12].y)
|
|
|
|
-- Fourth row: products 13-15
|
|
luaunit.assertTrue(productPositions[13].y == productPositions[14].y)
|
|
luaunit.assertTrue(productPositions[14].y == productPositions[15].y)
|
|
|
|
-- Different rows
|
|
luaunit.assertTrue(productPositions[1].y ~= productPositions[5].y)
|
|
luaunit.assertTrue(productPositions[5].y ~= productPositions[9].y)
|
|
luaunit.assertTrue(productPositions[9].y ~= productPositions[13].y)
|
|
|
|
-- Verify nested product card layouts
|
|
local product1 = productGrid.children[1]
|
|
product1:layoutChildren()
|
|
|
|
-- Verify product rating stars layout
|
|
local info = product1.children[2]
|
|
info:layoutChildren()
|
|
local rating = info.children[3]
|
|
rating:layoutChildren()
|
|
local stars = rating.children[1]
|
|
stars:layoutChildren()
|
|
|
|
-- All 5 stars should be on one line
|
|
luaunit.assertTrue(stars.children[1].y == stars.children[2].y)
|
|
luaunit.assertTrue(stars.children[2].y == stars.children[3].y)
|
|
luaunit.assertTrue(stars.children[3].y == stars.children[4].y)
|
|
luaunit.assertTrue(stars.children[4].y == stars.children[5].y)
|
|
|
|
-- Verify color variants wrapping
|
|
local pricing = info.children[4]
|
|
pricing:layoutChildren()
|
|
local variants = pricing.children[2]
|
|
variants:layoutChildren()
|
|
|
|
-- 4 variants should fit: 16*4 + 3*3 = 73 < 80px available
|
|
luaunit.assertTrue(variants.children[1].y == variants.children[2].y)
|
|
luaunit.assertTrue(variants.children[2].y == variants.children[3].y)
|
|
luaunit.assertTrue(variants.children[3].y == variants.children[4].y)
|
|
end
|
|
|
|
luaunit.LuaUnit.run()
|