Files
FlexLove/testing/__tests__/05_justify_content_tests.lua
2025-10-15 22:01:05 -04:00

1666 lines
47 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 05. Justify Content Alignment Tests
-- Tests for FlexLove justify content functionality
-- Load test framework and dependencies
package.path = package.path .. ";?.lua"
local luaunit = require("testing.luaunit")
require("testing.loveStub") -- Required to mock LOVE functions
local FlexLove = require("FlexLove")
local Gui, enums = FlexLove.GUI, FlexLove.enums
-- Import required enums
local Positioning = enums.Positioning
local FlexDirection = enums.FlexDirection
local JustifyContent = enums.JustifyContent
local AlignItems = enums.AlignItems
-- Test class for justify content functionality
TestJustifyContent = {}
function TestJustifyContent:setUp()
-- Clear any previous state if needed
Gui.destroy()
end
function TestJustifyContent:tearDown()
-- Clean up after each test
Gui.destroy()
end
-- Test 1: Horizontal Flex with JustifyContent.FLEX_START
function TestJustifyContent:testHorizontalFlexJustifyContentFlexStart()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 300,
height = 100,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.FLEX_START,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
local child3 = Gui.new({
id = "child3",
width = 70,
height = 35,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
container:addChild(child3)
-- With FLEX_START, children should be positioned from the start (left)
luaunit.assertEquals(child1.x, 0)
luaunit.assertEquals(child2.x, 50)
luaunit.assertEquals(child3.x, 110)
-- Y positions should be 0 (aligned to top by default)
luaunit.assertEquals(child1.y, 0)
luaunit.assertEquals(child2.y, 0)
luaunit.assertEquals(child3.y, 0)
end
-- Test 2: Horizontal Flex with JustifyContent.CENTER
function TestJustifyContent:testHorizontalFlexJustifyContentCenter()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 300,
height = 100,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.CENTER,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
-- Total child width: 50 + 60 = 110
-- Available space: 300 - 110 = 190
-- Center offset: 190 / 2 = 95
luaunit.assertEquals(child1.x, 95)
luaunit.assertEquals(child2.x, 145)
end
-- Test 3: Horizontal Flex with JustifyContent.FLEX_END
function TestJustifyContent:testHorizontalFlexJustifyContentFlexEnd()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 300,
height = 100,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.FLEX_END,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
-- Total child width: 50 + 60 = 110
-- Available space: 300 - 110 = 190
-- Children should be positioned from the end
luaunit.assertEquals(child1.x, 190)
luaunit.assertEquals(child2.x, 240)
end
-- Test 4: Horizontal Flex with JustifyContent.SPACE_BETWEEN
function TestJustifyContent:testHorizontalFlexJustifyContentSpaceBetween()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 300,
height = 100,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
local child3 = Gui.new({
id = "child3",
width = 40,
height = 35,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
container:addChild(child3)
-- Total child width: 50 + 60 + 40 = 150
-- Available space: 300 - 150 = 150
-- Space between 3 children: 150 / 2 = 75
luaunit.assertEquals(child1.x, 0)
luaunit.assertEquals(child2.x, 125) -- 0 + 50 + 75
luaunit.assertEquals(child3.x, 260) -- 125 + 60 + 75
end
-- Test 5: Horizontal Flex with JustifyContent.SPACE_AROUND
function TestJustifyContent:testHorizontalFlexJustifyContentSpaceAround()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 300,
height = 100,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_AROUND,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
-- Total child width: 50 + 60 = 110
-- Available space: 300 - 110 = 190
-- Space around each: 190 / 2 = 95 (FlexLove divides by number of children)
-- Start position: 95 / 2 = 47.5
-- Item spacing: 0 + 95 = 95
luaunit.assertEquals(child1.x, 47.5)
luaunit.assertEquals(child2.x, 192.5) -- 47.5 + 50 + 95
end
-- Test 6: Horizontal Flex with JustifyContent.SPACE_EVENLY
function TestJustifyContent:testHorizontalFlexJustifyContentSpaceEvenly()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 300,
height = 100,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_EVENLY,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
-- Total child width: 50 + 60 = 110
-- Available space: 300 - 110 = 190
-- Space evenly: 190 / 3 = 63.33... (equal spaces at start, between, and end)
local expectedSpace = 190 / 3
luaunit.assertAlmostEquals(child1.x, expectedSpace, 0.01)
luaunit.assertAlmostEquals(child2.x, expectedSpace + 50 + expectedSpace, 0.01)
end
-- Test 7: Vertical Flex with JustifyContent.FLEX_START
function TestJustifyContent:testVerticalFlexJustifyContentFlexStart()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 100,
height = 300,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.FLEX_START,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
local child3 = Gui.new({
id = "child3",
width = 70,
height = 35,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
container:addChild(child3)
-- With FLEX_START, children should be positioned from the start (top)
luaunit.assertEquals(child1.y, 0)
luaunit.assertEquals(child2.y, 30)
luaunit.assertEquals(child3.y, 70)
-- X positions should be 0 (aligned to left by default)
luaunit.assertEquals(child1.x, 0)
luaunit.assertEquals(child2.x, 0)
luaunit.assertEquals(child3.x, 0)
end
-- Test 8: Vertical Flex with JustifyContent.CENTER
function TestJustifyContent:testVerticalFlexJustifyContentCenter()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 100,
height = 300,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.CENTER,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
-- Total child height: 30 + 40 = 70
-- Available space: 300 - 70 = 230
-- Center offset: 230 / 2 = 115
luaunit.assertEquals(child1.y, 115)
luaunit.assertEquals(child2.y, 145)
end
-- Test 9: Vertical Flex with JustifyContent.FLEX_END
function TestJustifyContent:testVerticalFlexJustifyContentFlexEnd()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 100,
height = 300,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.FLEX_END,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
-- Total child height: 30 + 40 = 70
-- Available space: 300 - 70 = 230
-- Children should be positioned from the end
luaunit.assertEquals(child1.y, 230)
luaunit.assertEquals(child2.y, 260)
end
-- Test 10: Vertical Flex with JustifyContent.SPACE_BETWEEN
function TestJustifyContent:testVerticalFlexJustifyContentSpaceBetween()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 100,
height = 300,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
local child3 = Gui.new({
id = "child3",
width = 40,
height = 35,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
container:addChild(child3)
-- Total child height: 30 + 40 + 35 = 105
-- Available space: 300 - 105 = 195
-- Space between 3 children: 195 / 2 = 97.5
luaunit.assertEquals(child1.y, 0)
luaunit.assertEquals(child2.y, 127.5) -- 0 + 30 + 97.5
luaunit.assertEquals(child3.y, 265) -- 127.5 + 40 + 97.5
end
-- Test 11: Vertical Flex with JustifyContent.SPACE_AROUND
function TestJustifyContent:testVerticalFlexJustifyContentSpaceAround()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 100,
height = 300,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.SPACE_AROUND,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
-- Total child height: 30 + 40 = 70
-- Available space: 300 - 70 = 230
-- Space around each: 230 / 2 = 115 (FlexLove divides by number of children)
-- Start position: 115 / 2 = 57.5
-- Item spacing: 0 + 115 = 115
luaunit.assertEquals(child1.y, 57.5)
luaunit.assertEquals(child2.y, 202.5) -- 57.5 + 30 + 115
end
-- Test 12: Vertical Flex with JustifyContent.SPACE_EVENLY
function TestJustifyContent:testVerticalFlexJustifyContentSpaceEvenly()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 100,
height = 300,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.SPACE_EVENLY,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
-- Total child height: 30 + 40 = 70
-- Available space: 300 - 70 = 230
-- Space evenly: 230 / 3 = 76.67... (equal spaces at start, between, and end)
local expectedSpace = 230 / 3
luaunit.assertAlmostEquals(child1.y, expectedSpace, 0.01)
luaunit.assertAlmostEquals(child2.y, expectedSpace + 30 + expectedSpace, 0.01)
end
-- Test 13: JustifyContent with Single Child
function TestJustifyContent:testJustifyContentWithSingleChild()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 300,
height = 100,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.CENTER,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
container:addChild(child1)
-- With single child and CENTER, child should be centered
-- Available space: 300 - 50 = 250
-- Center offset: 250 / 2 = 125
luaunit.assertEquals(child1.x, 125)
end
-- Test 14: JustifyContent with No Available Space
function TestJustifyContent:testJustifyContentWithNoAvailableSpace()
local container = Gui.new({
id = "container",
x = 0,
y = 0,
width = 100,
height = 100,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 50,
height = 40,
positioning = Positioning.FLEX,
})
container:addChild(child1)
container:addChild(child2)
-- Children exactly fill container width (100)
-- Should fall back to FLEX_START behavior
luaunit.assertEquals(child1.x, 0)
luaunit.assertEquals(child2.x, 50)
end
-- Test 15: JustifyContent Preservation with Parent Coordinates
function TestJustifyContent:testJustifyContentWithParentCoordinates()
local parent = Gui.new({
id = "parent",
x = 50,
y = 30,
width = 400,
height = 200,
positioning = Positioning.ABSOLUTE,
})
local container = Gui.new({
id = "container",
x = 20,
y = 10,
width = 300,
height = 100,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.CENTER,
gap = 0,
})
local child1 = Gui.new({
id = "child1",
width = 50,
height = 30,
positioning = Positioning.FLEX,
})
local child2 = Gui.new({
id = "child2",
width = 60,
height = 40,
positioning = Positioning.FLEX,
})
parent:addChild(container)
container:addChild(child1)
container:addChild(child2)
-- Container should maintain its own coordinates since parent is ABSOLUTE
luaunit.assertEquals(container.x, 20) -- container keeps its own x
luaunit.assertEquals(container.y, 10) -- container keeps its own y
-- Children should be centered within container coordinate system
-- Total child width: 50 + 60 = 110
-- Available space: 300 - 110 = 190
-- Center offset: 190 / 2 = 95
-- Children are positioned in absolute coordinates: container.x + offset
luaunit.assertEquals(child1.x, 115) -- container.x(20) + center_offset(95)
luaunit.assertEquals(child2.x, 165) -- container.x(20) + center_offset(95) + child1.width(50)
end
-- Test 16: Complex navigation bar with space-between and nested elements
function TestJustifyContent:testComplexNavigationBarLayout()
local navbar = Gui.new({
id = "navbar",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
x = 0,
y = 0,
width = 1200,
height = 80,
gap = 0,
})
-- Logo section
local logoSection = Gui.new({
id = "logoSection",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
alignItems = AlignItems.CENTER,
width = 250,
height = 70,
gap = 15,
})
local logo = Gui.new({ id = "logo", width = 60, height = 50 })
local brandName = Gui.new({ id = "brandName", width = 120, height = 30 })
local beta = Gui.new({ id = "beta", width = 40, height = 20 })
logoSection:addChild(logo)
logoSection:addChild(brandName)
logoSection:addChild(beta)
-- Navigation menu
local navMenu = Gui.new({
id = "navMenu",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.CENTER,
width = 500,
height = 70,
gap = 30,
})
local menuItems = { "Home", "Products", "Solutions", "About", "Contact" }
for i, itemName in ipairs(menuItems) do
local menuItem = Gui.new({
id = "menuItem" .. itemName,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.CENTER,
alignItems = AlignItems.CENTER,
width = 80,
height = 60,
gap = 5,
})
local itemText = Gui.new({ id = "itemText" .. itemName, width = 70, height = 20 })
local itemDot = Gui.new({ id = "itemDot" .. itemName, width = 6, height = 6 })
menuItem:addChild(itemText)
menuItem:addChild(itemDot)
navMenu:addChild(menuItem)
end
-- Action buttons section
local actionsSection = Gui.new({
id = "actionsSection",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.FLEX_END,
alignItems = AlignItems.CENTER,
width = 300,
height = 70,
gap = 12,
})
local searchButton = Gui.new({ id = "searchButton", width = 40, height = 40 })
local loginButton = Gui.new({ id = "loginButton", width = 80, height = 35 })
local signupButton = Gui.new({ id = "signupButton", width = 100, height = 40 })
local mobileMenu = Gui.new({ id = "mobileMenu", width = 35, height = 35 })
actionsSection:addChild(searchButton)
actionsSection:addChild(loginButton)
actionsSection:addChild(signupButton)
actionsSection:addChild(mobileMenu)
navbar:addChild(logoSection)
navbar:addChild(navMenu)
navbar:addChild(actionsSection)
-- Verify space-between layout: elements should be distributed with equal space between
luaunit.assertEquals(logoSection.x, navbar.x)
luaunit.assertEquals(actionsSection.x + actionsSection.width, navbar.x + navbar.width)
-- Center menu should be positioned between logo and actions
local expectedMenuX = logoSection.x
+ logoSection.width
+ ((navbar.width - logoSection.width - navMenu.width - actionsSection.width) / 2)
luaunit.assertEquals(navMenu.x, expectedMenuX)
-- Verify nested center alignment in menu items
local firstMenuItem = navMenu.children[1]
local menuItemsWidth = 5 * 80 + 4 * 30 -- 5 items × 80px + 4 gaps × 30px = 520px
local menuStartX = navMenu.x + (navMenu.width - menuItemsWidth) / 2
luaunit.assertEquals(firstMenuItem.x, menuStartX)
-- Verify flex-end alignment in actions
local expectedActionsContentWidth = 40 + 80 + 100 + 35 + 3 * 12 -- widths + gaps = 291px
local expectedActionsStartX = actionsSection.x + actionsSection.width - expectedActionsContentWidth
luaunit.assertEquals(searchButton.x, expectedActionsStartX)
end
-- Test 17: Dashboard metrics layout with space-around
function TestJustifyContent:testDashboardMetricsSpaceAround()
local metricsContainer = Gui.new({
id = "metricsContainer",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_AROUND,
x = 0,
y = 0,
width = 1000,
height = 200,
gap = 0,
})
-- Create metric cards with different complexities
local metrics = {
{ title = "Revenue", hasChart = true, hasTrend = true },
{ title = "Users", hasChart = false, hasTrend = true },
{ title = "Orders", hasChart = true, hasTrend = false },
{ title = "Growth", hasChart = false, hasTrend = true },
}
for i, metric in ipairs(metrics) do
local metricCard = Gui.new({
id = "metricCard" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
width = 220,
height = 180,
gap = 10,
})
-- Card header
local cardHeader = Gui.new({
id = "cardHeader" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
alignItems = AlignItems.CENTER,
width = 200,
height = 30,
gap = 5,
})
local metricTitle = Gui.new({ id = "metricTitle" .. i, width = 100, height = 25 })
local metricIcon = Gui.new({ id = "metricIcon" .. i, width = 24, height = 24 })
cardHeader:addChild(metricTitle)
cardHeader:addChild(metricIcon)
-- Value section
local valueSection = Gui.new({
id = "valueSection" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.CENTER,
alignItems = AlignItems.CENTER,
width = 200,
height = 80,
gap = 8,
})
local mainValue = Gui.new({ id = "mainValue" .. i, width = 120, height = 40 })
local valueLabel = Gui.new({ id = "valueLabel" .. i, width = 80, height = 16 })
valueSection:addChild(mainValue)
valueSection:addChild(valueLabel)
if metric.hasTrend then
local trendIndicator = Gui.new({ id = "trendIndicator" .. i, width = 60, height = 20 })
valueSection:addChild(trendIndicator)
valueSection.height = 100
end
-- Bottom section (chart or additional info)
local bottomSection = Gui.new({
id = "bottomSection" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = metric.hasChart and JustifyContent.CENTER or JustifyContent.SPACE_EVENLY,
alignItems = AlignItems.CENTER,
width = 200,
height = 50,
gap = 5,
})
if metric.hasChart then
local miniChart = Gui.new({ id = "miniChart" .. i, width = 150, height = 40 })
bottomSection:addChild(miniChart)
else
-- Add comparison indicators
local prevPeriod = Gui.new({ id = "prevPeriod" .. i, width = 60, height = 20 })
local comparison = Gui.new({ id = "comparison" .. i, width = 40, height = 20 })
local target = Gui.new({ id = "target" .. i, width = 60, height = 20 })
bottomSection:addChild(prevPeriod)
bottomSection:addChild(comparison)
bottomSection:addChild(target)
end
metricCard:addChild(cardHeader)
metricCard:addChild(valueSection)
metricCard:addChild(bottomSection)
metricsContainer:addChild(metricCard)
end
-- Verify space-around distribution
local totalCardsWidth = 4 * 220 -- 880px
local availableSpace = 1000 - 880 -- 120px
local spaceAroundEach = availableSpace / 4 -- 30px around each card
local spaceAtEnds = spaceAroundEach / 2 -- 15px at each end
local firstCard = metricsContainer.children[1]
local secondCard = metricsContainer.children[2]
luaunit.assertEquals(firstCard.x, spaceAtEnds)
luaunit.assertEquals(secondCard.x, spaceAtEnds + 220 + spaceAroundEach)
-- Verify nested space-between in card headers
local firstCardHeader = firstCard.children[1]
local headerTitle = firstCardHeader.children[1]
local headerIcon = firstCardHeader.children[2]
luaunit.assertEquals(headerTitle.x, firstCardHeader.x)
luaunit.assertEquals(headerIcon.x + headerIcon.width, firstCardHeader.x + firstCardHeader.width)
end
-- Test 18: Complex form layout with varied justify content
function TestJustifyContent:testComplexFormJustifyContentLayout()
local formContainer = Gui.new({
id = "formContainer",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
x = 0,
y = 0,
width = 600,
height = 800,
gap = 25,
})
-- Form header with space-between
local formHeader = Gui.new({
id = "formHeader",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
alignItems = AlignItems.CENTER,
width = 580,
height = 60,
gap = 0,
})
local headerLeft = Gui.new({
id = "headerLeft",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
width = 200,
height = 50,
gap = 5,
})
local formTitle = Gui.new({ id = "formTitle", width = 180, height = 30 })
local formSubtitle = Gui.new({ id = "formSubtitle", width = 200, height = 15 })
headerLeft:addChild(formTitle)
headerLeft:addChild(formSubtitle)
local headerRight = Gui.new({
id = "headerRight",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.FLEX_END,
alignItems = AlignItems.CENTER,
width = 150,
height = 50,
gap = 10,
})
local helpButton = Gui.new({ id = "helpButton", width = 30, height = 30 })
local closeButton = Gui.new({ id = "closeButton", width = 30, height = 30 })
headerRight:addChild(helpButton)
headerRight:addChild(closeButton)
formHeader:addChild(headerLeft)
formHeader:addChild(headerRight)
-- Field sections with different alignments
local personalSection = Gui.new({
id = "personalSection",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
width = 580,
height = 250,
gap = 15,
})
local sectionTitle = Gui.new({
id = "sectionTitle",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.FLEX_START,
width = 580,
height = 30,
gap = 10,
})
local titleText = Gui.new({ id = "titleText", width = 150, height = 25 })
local titleIcon = Gui.new({ id = "titleIcon", width = 20, height = 20 })
sectionTitle:addChild(titleText)
sectionTitle:addChild(titleIcon)
-- Field rows with different layouts
local nameRow = Gui.new({
id = "nameRow",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
width = 580,
height = 60,
gap = 15,
})
local firstNameGroup = Gui.new({
id = "firstNameGroup",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
width = 275,
height = 55,
gap = 5,
})
local firstNameLabel = Gui.new({ id = "firstNameLabel", width = 80, height = 20 })
local firstNameInput = Gui.new({ id = "firstNameInput", width = 275, height = 30 })
firstNameGroup:addChild(firstNameLabel)
firstNameGroup:addChild(firstNameInput)
local lastNameGroup = Gui.new({
id = "lastNameGroup",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
width = 275,
height = 55,
gap = 5,
})
local lastNameLabel = Gui.new({ id = "lastNameLabel", width = 80, height = 20 })
local lastNameInput = Gui.new({ id = "lastNameInput", width = 275, height = 30 })
lastNameGroup:addChild(lastNameLabel)
lastNameGroup:addChild(lastNameInput)
nameRow:addChild(firstNameGroup)
nameRow:addChild(lastNameGroup)
-- Contact preferences with space-evenly
local contactRow = Gui.new({
id = "contactRow",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_EVENLY,
alignItems = AlignItems.CENTER,
width = 580,
height = 50,
gap = 0,
})
local emailOption = Gui.new({
id = "emailOption",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
alignItems = AlignItems.CENTER,
width = 120,
height = 40,
gap = 8,
})
Gui.new({ parent = emailOption, id = "emailCheckbox", width = 20, height = 20 })
Gui.new({ parent = emailOption, id = "emailLabel", width = 60, height = 18 })
local phoneOption = Gui.new({
id = "phoneOption",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
alignItems = AlignItems.CENTER,
width = 120,
height = 40,
gap = 8,
})
local phoneCheckbox = Gui.new({ id = "phoneCheckbox", width = 20, height = 20 })
local phoneLabel = Gui.new({ id = "phoneLabel", width = 60, height = 18 })
phoneOption:addChild(phoneCheckbox)
phoneOption:addChild(phoneLabel)
local smsOption = Gui.new({
id = "smsOption",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
alignItems = AlignItems.CENTER,
width = 100,
height = 40,
gap = 8,
})
local smsCheckbox = Gui.new({ id = "smsCheckbox", width = 20, height = 20 })
local smsLabel = Gui.new({ id = "smsLabel", width = 50, height = 18 })
smsOption:addChild(smsCheckbox)
smsOption:addChild(smsLabel)
contactRow:addChild(emailOption)
contactRow:addChild(phoneOption)
contactRow:addChild(smsOption)
personalSection:addChild(sectionTitle)
personalSection:addChild(nameRow)
personalSection:addChild(contactRow)
-- Form actions with varied justification
local actionsSection = Gui.new({
id = "actionsSection",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
width = 580,
height = 120,
gap = 20,
})
local primaryActions = Gui.new({
id = "primaryActions",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.FLEX_END,
alignItems = AlignItems.CENTER,
width = 580,
height = 45,
gap = 15,
})
local cancelButton = Gui.new({ id = "cancelButton", width = 80, height = 40 })
local saveButton = Gui.new({ id = "saveButton", width = 100, height = 40 })
local submitButton = Gui.new({ id = "submitButton", width = 120, height = 40 })
primaryActions:addChild(cancelButton)
primaryActions:addChild(saveButton)
primaryActions:addChild(submitButton)
local secondaryActions = Gui.new({
id = "secondaryActions",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.CENTER,
alignItems = AlignItems.CENTER,
width = 580,
height = 35,
gap = 25,
})
local resetButton = Gui.new({ id = "resetButton", width = 70, height = 30 })
local previewButton = Gui.new({ id = "previewButton", width = 80, height = 30 })
secondaryActions:addChild(resetButton)
secondaryActions:addChild(previewButton)
actionsSection:addChild(primaryActions)
actionsSection:addChild(secondaryActions)
formContainer:addChild(formHeader)
formContainer:addChild(personalSection)
formContainer:addChild(actionsSection)
-- Verify complex justify content behaviors
-- Header space-between
luaunit.assertEquals(headerLeft.x, formHeader.x)
luaunit.assertEquals(headerRight.x + headerRight.width, formHeader.x + formHeader.width)
-- Name row space-between
luaunit.assertEquals(firstNameGroup.x, nameRow.x)
luaunit.assertEquals(lastNameGroup.x + lastNameGroup.width, nameRow.x + nameRow.width)
-- Contact preferences space-evenly
local totalOptionsWidth = 120 + 120 + 100 -- 340px
local availableSpace = 580 - 340 -- 240px
local evenSpacing = 240 / 4 -- 60px (spaces before, between, between, after)
luaunit.assertEquals(emailOption.x, contactRow.x + evenSpacing)
luaunit.assertEquals(phoneOption.x, emailOption.x + emailOption.width + evenSpacing)
luaunit.assertEquals(smsOption.x, phoneOption.x + phoneOption.width + evenSpacing)
-- Primary actions flex-end
local totalPrimaryWidth = 80 + 100 + 120 + 2 * 15 -- 330px including gaps
local expectedPrimaryStartX = primaryActions.x + primaryActions.width - totalPrimaryWidth
luaunit.assertEquals(cancelButton.x, expectedPrimaryStartX)
-- Secondary actions center
local totalSecondaryWidth = 70 + 80 + 25 -- 175px including gap
local expectedSecondaryStartX = secondaryActions.x + (secondaryActions.width - totalSecondaryWidth) / 2
luaunit.assertEquals(resetButton.x, expectedSecondaryStartX)
end
-- Test 19: Grid-like layout with justify content variations
function TestJustifyContent:testGridLayoutJustifyContentVariations()
local gridContainer = Gui.new({
id = "gridContainer",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
x = 0,
y = 0,
width = 800,
height = 600,
gap = 20,
})
-- Row 1: Space-between
local row1 = Gui.new({
id = "row1",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
width = 780,
height = 120,
gap = 0,
})
for i = 1, 4 do
local card = Gui.new({
id = "row1Card" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.CENTER,
alignItems = AlignItems.CENTER,
width = 150,
height = 100,
gap = 10,
})
local cardIcon = Gui.new({ id = "row1Icon" .. i, width = 40, height = 40 })
local cardLabel = Gui.new({ id = "row1Label" .. i, width = 100, height = 20 })
card:addChild(cardIcon)
card:addChild(cardLabel)
row1:addChild(card)
end
-- Row 2: Space-around
local row2 = Gui.new({
id = "row2",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_AROUND,
width = 780,
height = 120,
gap = 0,
})
for i = 1, 3 do
local card = Gui.new({
id = "row2Card" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
width = 200,
height = 100,
gap = 5,
})
local cardHeader = Gui.new({
id = "row2Header" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
width = 180,
height = 25,
gap = 0,
})
local headerTitle = Gui.new({ id = "row2HeaderTitle" .. i, width = 100, height = 20 })
local headerIcon = Gui.new({ id = "row2HeaderIcon" .. i, width = 20, height = 20 })
cardHeader:addChild(headerTitle)
cardHeader:addChild(headerIcon)
local cardContent = Gui.new({ id = "row2Content" .. i, width = 180, height = 40 })
local cardFooter = Gui.new({ id = "row2Footer" .. i, width = 180, height = 20 })
card:addChild(cardHeader)
card:addChild(cardContent)
card:addChild(cardFooter)
row2:addChild(card)
end
-- Row 3: Space-evenly
local row3 = Gui.new({
id = "row3",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_EVENLY,
width = 780,
height = 120,
gap = 0,
})
for i = 1, 5 do
local item = Gui.new({
id = "row3Item" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.FLEX_END,
alignItems = AlignItems.CENTER,
width = 100,
height = 100,
gap = 5,
})
local itemValue = Gui.new({ id = "row3Value" .. i, width = 60, height = 30 })
local itemLabel = Gui.new({ id = "row3Label" .. i, width = 80, height = 15 })
local itemTrend = Gui.new({ id = "row3Trend" .. i, width = 40, height = 12 })
item:addChild(itemValue)
item:addChild(itemLabel)
item:addChild(itemTrend)
row3:addChild(item)
end
-- Row 4: Center with overflow behavior
local row4 = Gui.new({
id = "row4",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.CENTER,
width = 780,
height = 120,
gap = 10,
})
-- Create many items that might overflow
for i = 1, 8 do
local chip = Gui.new({
id = "row4Chip" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.CENTER,
alignItems = AlignItems.CENTER,
width = 90,
height = 30,
gap = 5,
})
local chipIcon = Gui.new({ id = "row4ChipIcon" .. i, width = 16, height = 16 })
local chipText = Gui.new({ id = "row4ChipText" .. i, width = 60, height = 14 })
chip:addChild(chipIcon)
chip:addChild(chipText)
row4:addChild(chip)
end
gridContainer:addChild(row1)
gridContainer:addChild(row2)
gridContainer:addChild(row3)
gridContainer:addChild(row4)
-- Verify row 1 space-between (4 cards, 150px each)
local row1Card1 = row1.children[1]
local row1Card4 = row1.children[4]
luaunit.assertEquals(row1Card1.x, row1.x)
luaunit.assertEquals(row1Card4.x + row1Card4.width, row1.x + row1.width)
-- Verify row 2 space-around (3 cards, 200px each)
local totalRow2Width = 3 * 200 -- 600px
local row2AvailableSpace = 780 - 600 -- 180px
local row2SpaceAround = 180 / 3 -- 60px around each
local row2SpaceAtEnds = 60 / 2 -- 30px at ends
local row2Card1 = row2.children[1]
luaunit.assertEquals(row2Card1.x, row2.x + row2SpaceAtEnds)
-- Verify row 3 space-evenly (5 items, 100px each)
local totalRow3Width = 5 * 100 -- 500px
local row3AvailableSpace = 780 - 500 -- 280px
local row3EvenSpacing = 280 / 6 -- 46.67px (6 spaces: before, between×4, after)
local row3Item1 = row3.children[1]
luaunit.assertAlmostEquals(row3Item1.x, row3.x + row3EvenSpacing, 0.1)
-- Verify row 4 center behavior (8 chips, 90px each + 7 gaps of 10px = 790px)
-- Should overflow slightly but center the content
local totalRow4Width = 8 * 90 + 7 * 10 -- 790px (larger than container)
local row4Offset = (row4.width - totalRow4Width) / 2 -- Should be negative
local row4Chip1 = row4.children[1]
-- When content is larger than container, should start at calculated offset (possibly negative)
luaunit.assertEquals(row4Chip1.x, row4.x + row4Offset)
-- Verify nested justify content in cards
local row2Card1Header = row2.children[1].children[1]
local headerTitle = row2Card1Header.children[1]
local headerIcon = row2Card1Header.children[2]
luaunit.assertEquals(headerTitle.x, row2Card1Header.x)
luaunit.assertEquals(headerIcon.x + headerIcon.width, row2Card1Header.x + row2Card1Header.width)
end
-- Test 20: Multi-level nested justify content with modal dialogs
function TestJustifyContent:testMultiLevelNestedModalJustifyContent()
local modalOverlay = Gui.new({
id = "modalOverlay",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.CENTER,
alignItems = AlignItems.CENTER,
x = 0,
y = 0,
width = 1200,
height = 800,
gap = 0,
})
local modal = Gui.new({
id = "modal",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
width = 600,
height = 500,
gap = 0,
})
-- Modal header with space-between
local modalHeader = Gui.new({
id = "modalHeader",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
alignItems = AlignItems.CENTER,
width = 580,
height = 60,
gap = 0,
})
local headerLeft = Gui.new({
id = "headerLeft",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
alignItems = AlignItems.CENTER,
width = 200,
height = 50,
gap = 12,
})
local modalIcon = Gui.new({ id = "modalIcon", width = 24, height = 24 })
local modalTitle = Gui.new({ id = "modalTitle", width = 150, height = 30 })
headerLeft:addChild(modalIcon)
headerLeft:addChild(modalTitle)
local headerRight = Gui.new({
id = "headerRight",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.FLEX_END,
alignItems = AlignItems.CENTER,
width = 100,
height = 50,
gap = 8,
})
local minimizeButton = Gui.new({ id = "minimizeButton", width = 30, height = 30 })
local closeButton = Gui.new({ id = "closeButton", width = 30, height = 30 })
headerRight:addChild(minimizeButton)
headerRight:addChild(closeButton)
modalHeader:addChild(headerLeft)
modalHeader:addChild(headerRight)
-- Modal content with complex nested layouts
local modalContent = Gui.new({
id = "modalContent",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
width = 580,
height = 380,
gap = 20,
})
-- Tab navigation
local tabNavigation = Gui.new({
id = "tabNavigation",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_EVENLY,
width = 580,
height = 50,
gap = 0,
})
local tabs = { "General", "Advanced", "Security", "Notifications" }
for i, tabName in ipairs(tabs) do
local tab = Gui.new({
id = "tab" .. tabName,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.CENTER,
alignItems = AlignItems.CENTER,
width = 120,
height = 45,
gap = 5,
})
local tabText = Gui.new({ id = "tabText" .. tabName, width = 80, height = 18 })
local tabIndicator = Gui.new({ id = "tabIndicator" .. tabName, width = 60, height = 3 })
tab:addChild(tabText)
tab:addChild(tabIndicator)
tabNavigation:addChild(tab)
end
-- Content area with settings rows
local settingsArea = Gui.new({
id = "settingsArea",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
width = 580,
height = 250,
gap = 15,
})
-- Setting rows with different alignments
for i = 1, 4 do
local settingRow = Gui.new({
id = "settingRow" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = i % 2 == 1 and JustifyContent.SPACE_BETWEEN or JustifyContent.FLEX_START,
alignItems = AlignItems.CENTER,
width = 560,
height = 50,
gap = 15,
})
local settingInfo = Gui.new({
id = "settingInfo" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.VERTICAL,
justifyContent = JustifyContent.CENTER,
width = 300,
height = 40,
gap = 3,
})
local settingLabel = Gui.new({ id = "settingLabel" .. i, width = 200, height = 20 })
local settingDescription = Gui.new({ id = "settingDescription" .. i, width = 280, height = 14 })
settingInfo:addChild(settingLabel)
settingInfo:addChild(settingDescription)
local settingControl = Gui.new({
id = "settingControl" .. i,
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.CENTER,
alignItems = AlignItems.CENTER,
width = i % 2 == 1 and 100 or 200,
height = 35,
gap = 8,
})
if i % 2 == 1 then
-- Toggle switch
local toggle = Gui.new({ id = "toggle" .. i, width = 60, height = 30 })
settingControl:addChild(toggle)
else
-- Dropdown or input
local input = Gui.new({ id = "input" .. i, width = 120, height = 30 })
local button = Gui.new({ id = "button" .. i, width = 60, height = 28 })
settingControl:addChild(input)
settingControl:addChild(button)
end
settingRow:addChild(settingInfo)
settingRow:addChild(settingControl)
settingsArea:addChild(settingRow)
end
modalContent:addChild(tabNavigation)
modalContent:addChild(settingsArea)
-- Modal footer with action buttons
local modalFooter = Gui.new({
id = "modalFooter",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.SPACE_BETWEEN,
alignItems = AlignItems.CENTER,
width = 580,
height = 60,
gap = 0,
})
local footerLeft = Gui.new({
id = "footerLeft",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.FLEX_START,
alignItems = AlignItems.CENTER,
width = 200,
height = 50,
gap = 10,
})
local resetButton = Gui.new({ id = "resetButton", width = 80, height = 35 })
local helpLink = Gui.new({ id = "helpLink", width = 60, height = 20 })
footerLeft:addChild(resetButton)
footerLeft:addChild(helpLink)
local footerRight = Gui.new({
id = "footerRight",
positioning = Positioning.FLEX,
flexDirection = FlexDirection.HORIZONTAL,
justifyContent = JustifyContent.FLEX_END,
alignItems = AlignItems.CENTER,
width = 250,
height = 50,
gap = 12,
})
local cancelButton = Gui.new({ id = "cancelButton", width = 70, height = 35 })
local applyButton = Gui.new({ id = "applyButton", width = 70, height = 35 })
local saveButton = Gui.new({ id = "saveButton", width = 80, height = 35 })
footerRight:addChild(cancelButton)
footerRight:addChild(applyButton)
footerRight:addChild(saveButton)
modalFooter:addChild(footerLeft)
modalFooter:addChild(footerRight)
modal:addChild(modalHeader)
modal:addChild(modalContent)
modal:addChild(modalFooter)
modalOverlay:addChild(modal)
-- Verify modal is centered in overlay
local expectedModalX = modalOverlay.x + (modalOverlay.width - modal.width) / 2
luaunit.assertEquals(modal.x, expectedModalX)
-- Verify modal space-between layout
luaunit.assertEquals(modalHeader.y, modal.y)
luaunit.assertEquals(modalFooter.y + modalFooter.height, modal.y + modal.height)
-- Verify header space-between
luaunit.assertEquals(headerLeft.x, modalHeader.x)
luaunit.assertEquals(headerRight.x + headerRight.width, modalHeader.x + modalHeader.width)
-- Verify tab space-evenly distribution
local totalTabsWidth = 4 * 120 -- 480px
local tabAvailableSpace = 580 - 480 -- 100px
local tabEvenSpacing = 100 / 5 -- 20px (5 spaces: before, between×3, after)
local firstTab = tabNavigation.children[1]
luaunit.assertEquals(firstTab.x, tabNavigation.x + tabEvenSpacing)
-- Verify setting rows alternate justification
local setting1 = settingsArea.children[1] -- space-between
local setting2 = settingsArea.children[2] -- flex-start
local setting1Info = setting1.children[1]
local setting1Control = setting1.children[2]
luaunit.assertEquals(setting1Info.x, setting1.x)
luaunit.assertEquals(setting1Control.x + setting1Control.width, setting1.x + setting1.width)
local setting2Info = setting2.children[1]
local setting2Control = setting2.children[2]
luaunit.assertEquals(setting2Info.x, setting2.x)
luaunit.assertEquals(setting2Control.x, setting2Info.x + setting2Info.width + setting2.gap)
-- Verify footer space-between
luaunit.assertEquals(footerLeft.x, modalFooter.x)
luaunit.assertEquals(footerRight.x + footerRight.width, modalFooter.x + modalFooter.width)
-- Verify nested button layouts in footer
local footerRightFirstButton = footerRight.children[1]
local footerRightLastButton = footerRight.children[3]
local expectedFooterRightStartX = footerRight.x + footerRight.width - (70 + 70 + 80 + 2 * 12)
luaunit.assertEquals(footerRightFirstButton.x, expectedFooterRightStartX)
end
luaunit.LuaUnit.run()