continuing testing
This commit is contained in:
30
AGENTS.md
Normal file
30
AGENTS.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# FlexLöve Agent Guidelines
|
||||
|
||||
## Testing
|
||||
- **Run all tests**: `lua testing/runAll.lua` (coverage report in `luacov.report.out`)
|
||||
- **Run single test**: `lua testing/__tests__/<test_file>.lua`
|
||||
- **Test immediate mode**: Call `FlexLove.setMode("immediate")` in `setUp()`, then `FlexLove.beginFrame()`/`FlexLove.endFrame()` to trigger layout
|
||||
|
||||
## Code Style
|
||||
- **Modules**: Use `local ModuleName = {}` pattern, return table at end
|
||||
- **Constructors**: `ClassName.new(props)` → instance (always returns, never nil)
|
||||
- **Instance methods**: `instance:methodName()` with colon syntax
|
||||
- **Static methods**: `ClassName.methodName()` with dot syntax
|
||||
- **Private fields**: Prefix with `_` (e.g., `self._internalState`)
|
||||
- **LuaDoc annotations**: Use `---@param`, `---@return`, `---@class`, `---@field` for all public APIs
|
||||
- **Error handling**: Use `ErrorHandler.error(module, message)` for critical errors, `ErrorHandler.warn(module, message)` for warnings
|
||||
- **String format**: Use `string.format()` for complex strings, avoid concatenation
|
||||
- **Auto-sizing**: Omit `width`/`height` properties (NOT `width = "auto"`)
|
||||
|
||||
## Architecture
|
||||
- **Immediate mode**: Elements recreated each frame, layout triggered by `endFrame()` → `layoutChildren()` called on top-level elements
|
||||
- **Retained mode**: Elements persist, must manually update properties (default)
|
||||
- **Dependencies**: Pass via `deps` table parameter in constructors (e.g., `{utils, ErrorHandler, Units}`)
|
||||
- **Layout flow**: `Element.new()` → `layoutChildren()` on construction → `resize()` on viewport change → `layoutChildren()` again
|
||||
- **CSS positioning**: `top/right/bottom/left` applied via `LayoutEngine:applyPositioningOffsets()` for absolute/relative containers
|
||||
|
||||
## Common Patterns
|
||||
- **Return values**: Single value OR `value, errorString` (nil on success for error)
|
||||
- **Enums**: Access via `utils.enums.EnumName.VALUE` (e.g., `Positioning.FLEX`)
|
||||
- **Units**: Parse with `Units.parse(value)` → `value, unit`, resolve with `Units.resolve(value, unit, viewportW, viewportH, parentSize)`
|
||||
- **Colors**: Use `Color.new(r, g, b, a)` (0-1 range) or `Color.fromHex("#RRGGBB")`
|
||||
@@ -11,8 +11,9 @@ local Grid = {}
|
||||
--- Layout grid items within a grid container using simple row/column counts
|
||||
---@param element Element -- Grid container element
|
||||
function Grid.layoutGridItems(element)
|
||||
local rows = element.gridRows or 1
|
||||
local columns = element.gridColumns or 1
|
||||
-- Ensure valid row/column counts (must be at least 1 to avoid division by zero)
|
||||
local rows = element.gridRows and element.gridRows > 0 and element.gridRows or 1
|
||||
local columns = element.gridColumns and element.gridColumns > 0 and element.gridColumns or 1
|
||||
|
||||
-- Calculate space reserved by absolutely positioned siblings
|
||||
local reservedLeft = 0
|
||||
|
||||
@@ -154,6 +154,11 @@ function LayoutEngine:layoutChildren()
|
||||
self:applyPositioningOffsets(child)
|
||||
end
|
||||
end
|
||||
|
||||
-- Detect overflow after children positioning
|
||||
if self.element._detectOverflow then
|
||||
self.element:_detectOverflow()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@@ -125,14 +125,16 @@ function ScrollManager:detectOverflow()
|
||||
for _, child in ipairs(element.children) do
|
||||
-- Skip absolutely positioned children (they don't contribute to overflow)
|
||||
if not child._explicitlyAbsolute then
|
||||
-- Calculate child position relative to content area
|
||||
local childLeft = child.x - contentX
|
||||
local childTop = child.y - contentY
|
||||
local childRight = childLeft + child:getBorderBoxWidth() + child.margin.right
|
||||
local childBottom = childTop + child:getBorderBoxHeight() + child.margin.bottom
|
||||
-- Calculate child's margin box bounds relative to content area
|
||||
-- child.x/y is the border-box position, margins extend outside this
|
||||
local childMarginLeft = child.x - contentX - child.margin.left
|
||||
local childMarginTop = child.y - contentY - child.margin.top
|
||||
local childMarginRight = child.x - contentX + child:getBorderBoxWidth() + child.margin.right
|
||||
local childMarginBottom = child.y - contentY + child:getBorderBoxHeight() + child.margin.bottom
|
||||
|
||||
maxX = math.max(maxX, childRight)
|
||||
maxY = math.max(maxY, childBottom)
|
||||
-- Track the maximum extents (we ignore negative space from margins)
|
||||
maxX = math.max(maxX, childMarginRight)
|
||||
maxY = math.max(maxY, childMarginBottom)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -140,9 +142,10 @@ function ScrollManager:detectOverflow()
|
||||
self._contentWidth = maxX
|
||||
self._contentHeight = maxY
|
||||
|
||||
-- Detect overflow
|
||||
local containerWidth = element.width
|
||||
local containerHeight = element.height
|
||||
-- Detect overflow (compare against content area, not total element size)
|
||||
-- The content area excludes padding
|
||||
local containerWidth = element.width - element.padding.left - element.padding.right
|
||||
local containerHeight = element.height - element.padding.top - element.padding.bottom
|
||||
|
||||
self._overflowX = self._contentWidth > containerWidth
|
||||
self._overflowY = self._contentHeight > containerHeight
|
||||
|
||||
490
testing/__tests__/grid_test.lua
Normal file
490
testing/__tests__/grid_test.lua
Normal file
@@ -0,0 +1,490 @@
|
||||
-- Test suite for Grid layout functionality
|
||||
-- Grid layout has 0% test coverage despite being integrated into the system
|
||||
package.path = package.path .. ";./?.lua;./modules/?.lua"
|
||||
|
||||
require("testing.loveStub")
|
||||
local luaunit = require("testing.luaunit")
|
||||
local FlexLove = require("FlexLove")
|
||||
|
||||
TestGridLayout = {}
|
||||
|
||||
function TestGridLayout:setUp()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
end
|
||||
|
||||
function TestGridLayout:tearDown()
|
||||
FlexLove.endFrame()
|
||||
end
|
||||
|
||||
-- Test basic grid layout with default 1x1 grid
|
||||
function TestGridLayout:test_default_grid_single_child()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 300,
|
||||
positioning = "grid"
|
||||
-- Default: gridRows=1, gridColumns=1
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child1",
|
||||
parent = container,
|
||||
width = 50, -- Will be stretched by grid
|
||||
height = 50
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Child should be stretched to fill the entire grid cell
|
||||
luaunit.assertEquals(child.x, 0, "Child should be at x=0")
|
||||
luaunit.assertEquals(child.y, 0, "Child should be at y=0")
|
||||
luaunit.assertEquals(child.width, 400, "Child should be stretched to container width")
|
||||
luaunit.assertEquals(child.height, 300, "Child should be stretched to container height")
|
||||
end
|
||||
|
||||
-- Test 2x2 grid layout
|
||||
function TestGridLayout:test_2x2_grid_four_children()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2
|
||||
})
|
||||
|
||||
local children = {}
|
||||
for i = 1, 4 do
|
||||
children[i] = FlexLove.new({
|
||||
id = "child" .. i,
|
||||
parent = container,
|
||||
width = 50,
|
||||
height = 50
|
||||
})
|
||||
end
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Each cell should be 200x200
|
||||
-- Child 1: top-left (0, 0)
|
||||
luaunit.assertEquals(children[1].x, 0, "Child 1 should be at x=0")
|
||||
luaunit.assertEquals(children[1].y, 0, "Child 1 should be at y=0")
|
||||
luaunit.assertEquals(children[1].width, 200, "Cell width should be 200")
|
||||
luaunit.assertEquals(children[1].height, 200, "Cell height should be 200")
|
||||
|
||||
-- Child 2: top-right (200, 0)
|
||||
luaunit.assertEquals(children[2].x, 200, "Child 2 should be at x=200")
|
||||
luaunit.assertEquals(children[2].y, 0, "Child 2 should be at y=0")
|
||||
|
||||
-- Child 3: bottom-left (0, 200)
|
||||
luaunit.assertEquals(children[3].x, 0, "Child 3 should be at x=0")
|
||||
luaunit.assertEquals(children[3].y, 200, "Child 3 should be at y=200")
|
||||
|
||||
-- Child 4: bottom-right (200, 200)
|
||||
luaunit.assertEquals(children[4].x, 200, "Child 4 should be at x=200")
|
||||
luaunit.assertEquals(children[4].y, 200, "Child 4 should be at y=200")
|
||||
end
|
||||
|
||||
-- Test grid with column and row gaps
|
||||
function TestGridLayout:test_grid_with_gaps()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 420, -- 2 cells * 200 + 1 gap * 20
|
||||
height = 320, -- 2 cells * 150 + 1 gap * 20
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2,
|
||||
columnGap = 20,
|
||||
rowGap = 20
|
||||
})
|
||||
|
||||
local children = {}
|
||||
for i = 1, 4 do
|
||||
children[i] = FlexLove.new({
|
||||
id = "child" .. i,
|
||||
parent = container,
|
||||
width = 50,
|
||||
height = 50
|
||||
})
|
||||
end
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Cell size: (420 - 20) / 2 = 200, (320 - 20) / 2 = 150
|
||||
luaunit.assertEquals(children[1].width, 200, "Cell width should be 200")
|
||||
luaunit.assertEquals(children[1].height, 150, "Cell height should be 150")
|
||||
|
||||
-- Child 2 should be offset by cell width + gap
|
||||
luaunit.assertEquals(children[2].x, 220, "Child 2 x = 200 + 20 gap")
|
||||
luaunit.assertEquals(children[2].y, 0, "Child 2 should be at y=0")
|
||||
|
||||
-- Child 3 should be offset by cell height + gap
|
||||
luaunit.assertEquals(children[3].x, 0, "Child 3 should be at x=0")
|
||||
luaunit.assertEquals(children[3].y, 170, "Child 3 y = 150 + 20 gap")
|
||||
end
|
||||
|
||||
-- Test grid with more children than cells (overflow)
|
||||
function TestGridLayout:test_grid_overflow_children()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 200,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2
|
||||
-- Only 4 cells available
|
||||
})
|
||||
|
||||
local children = {}
|
||||
for i = 1, 6 do -- 6 children, but only 4 cells
|
||||
children[i] = FlexLove.new({
|
||||
id = "child" .. i,
|
||||
parent = container,
|
||||
width = 50,
|
||||
height = 50
|
||||
})
|
||||
end
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- First 4 children should be positioned
|
||||
luaunit.assertNotNil(children[1].x, "Child 1 should be positioned")
|
||||
luaunit.assertNotNil(children[4].x, "Child 4 should be positioned")
|
||||
|
||||
-- Children 5 and 6 should NOT be positioned (or positioned at 0,0 by default)
|
||||
-- This tests the overflow behavior: row >= rows breaks the loop
|
||||
end
|
||||
|
||||
-- Test grid with alignItems center
|
||||
function TestGridLayout:test_grid_align_center()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2,
|
||||
alignItems = "center"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child1",
|
||||
parent = container,
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Cell is 200x200, child is 100x100, should be centered
|
||||
-- Center position: (200 - 100) / 2 = 50
|
||||
luaunit.assertEquals(child.x, 50, "Child should be centered horizontally in cell")
|
||||
luaunit.assertEquals(child.y, 50, "Child should be centered vertically in cell")
|
||||
luaunit.assertEquals(child.width, 100, "Child width should not be stretched")
|
||||
luaunit.assertEquals(child.height, 100, "Child height should not be stretched")
|
||||
end
|
||||
|
||||
-- Test grid with alignItems flex-start
|
||||
function TestGridLayout:test_grid_align_flex_start()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2,
|
||||
alignItems = "flex-start"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child1",
|
||||
parent = container,
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Child should be at top-left of cell
|
||||
luaunit.assertEquals(child.x, 0, "Child should be at left of cell")
|
||||
luaunit.assertEquals(child.y, 0, "Child should be at top of cell")
|
||||
luaunit.assertEquals(child.width, 100, "Child width should not be stretched")
|
||||
luaunit.assertEquals(child.height, 100, "Child height should not be stretched")
|
||||
end
|
||||
|
||||
-- Test grid with alignItems flex-end
|
||||
function TestGridLayout:test_grid_align_flex_end()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2,
|
||||
alignItems = "flex-end"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child1",
|
||||
parent = container,
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Cell is 200x200, child is 100x100, should be at bottom-right
|
||||
luaunit.assertEquals(child.x, 100, "Child should be at right of cell (200 - 100)")
|
||||
luaunit.assertEquals(child.y, 100, "Child should be at bottom of cell (200 - 100)")
|
||||
luaunit.assertEquals(child.width, 100, "Child width should not be stretched")
|
||||
luaunit.assertEquals(child.height, 100, "Child height should not be stretched")
|
||||
end
|
||||
|
||||
-- Test grid with padding
|
||||
function TestGridLayout:test_grid_with_padding()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 500, -- Total width
|
||||
height = 500,
|
||||
padding = { top = 50, right = 50, bottom = 50, left = 50 },
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child1",
|
||||
parent = container,
|
||||
width = 50,
|
||||
height = 50
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Available space: 500 - 50 - 50 = 400
|
||||
-- Cell size: 400 / 2 = 200
|
||||
-- Child should be positioned at padding.left, padding.top
|
||||
luaunit.assertEquals(child.x, 50, "Child x should account for left padding")
|
||||
luaunit.assertEquals(child.y, 50, "Child y should account for top padding")
|
||||
luaunit.assertEquals(child.width, 200, "Cell width should be 200")
|
||||
luaunit.assertEquals(child.height, 200, "Cell height should be 200")
|
||||
end
|
||||
|
||||
-- Test grid with absolutely positioned child (should be skipped in grid layout)
|
||||
function TestGridLayout:test_grid_with_absolute_child()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2
|
||||
})
|
||||
|
||||
-- Regular child
|
||||
local child1 = FlexLove.new({
|
||||
id = "child1",
|
||||
parent = container,
|
||||
width = 50,
|
||||
height = 50
|
||||
})
|
||||
|
||||
-- Absolutely positioned child (should be ignored by grid layout)
|
||||
local child2 = FlexLove.new({
|
||||
id = "child2",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
x = 10,
|
||||
y = 10,
|
||||
width = 30,
|
||||
height = 30
|
||||
})
|
||||
|
||||
-- Another regular child
|
||||
local child3 = FlexLove.new({
|
||||
id = "child3",
|
||||
parent = container,
|
||||
width = 50,
|
||||
height = 50
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- child1 should be in first grid cell (0, 0)
|
||||
luaunit.assertEquals(child1.x, 0, "Child 1 should be at x=0")
|
||||
luaunit.assertEquals(child1.y, 0, "Child 1 should be at y=0")
|
||||
|
||||
-- child2 should keep its absolute position
|
||||
luaunit.assertEquals(child2.x, 10, "Absolute child should keep x=10")
|
||||
luaunit.assertEquals(child2.y, 10, "Absolute child should keep y=10")
|
||||
|
||||
-- child3 should be in second grid cell (200, 0), not third
|
||||
luaunit.assertEquals(child3.x, 200, "Child 3 should be in second cell at x=200")
|
||||
luaunit.assertEquals(child3.y, 0, "Child 3 should be in second cell at y=0")
|
||||
end
|
||||
|
||||
-- Test edge case: empty grid
|
||||
function TestGridLayout:test_empty_grid()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2
|
||||
-- No children
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Should not crash
|
||||
luaunit.assertEquals(#container.children, 0, "Grid should have no children")
|
||||
end
|
||||
|
||||
-- Test edge case: grid with 0 columns or rows
|
||||
function TestGridLayout:test_grid_zero_dimensions()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "grid",
|
||||
gridRows = 0, -- Invalid: 0 rows
|
||||
gridColumns = 0 -- Invalid: 0 columns
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child1",
|
||||
parent = container,
|
||||
width = 50,
|
||||
height = 50
|
||||
})
|
||||
|
||||
-- This might cause division by zero or other errors
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Test passes if it doesn't crash
|
||||
luaunit.assertTrue(true, "Grid with 0 dimensions should not crash")
|
||||
end
|
||||
|
||||
-- Test nested grids
|
||||
function TestGridLayout:test_nested_grids()
|
||||
local outerGrid = FlexLove.new({
|
||||
id = "outer",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2
|
||||
})
|
||||
|
||||
-- First cell contains another grid
|
||||
local innerGrid = FlexLove.new({
|
||||
id = "inner",
|
||||
parent = outerGrid,
|
||||
width = 200,
|
||||
height = 200,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2
|
||||
})
|
||||
|
||||
-- Add children to inner grid
|
||||
for i = 1, 4 do
|
||||
FlexLove.new({
|
||||
id = "inner_child" .. i,
|
||||
parent = innerGrid,
|
||||
width = 25,
|
||||
height = 25
|
||||
})
|
||||
end
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Inner grid should be positioned in first cell of outer grid
|
||||
luaunit.assertEquals(innerGrid.x, 0, "Inner grid should be at x=0")
|
||||
luaunit.assertEquals(innerGrid.y, 0, "Inner grid should be at y=0")
|
||||
luaunit.assertEquals(#innerGrid.children, 4, "Inner grid should have 4 children")
|
||||
end
|
||||
|
||||
-- Test grid with reserved space from absolute children
|
||||
function TestGridLayout:test_grid_with_reserved_space()
|
||||
local container = FlexLove.new({
|
||||
id = "grid",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "grid",
|
||||
gridRows = 2,
|
||||
gridColumns = 2
|
||||
})
|
||||
|
||||
-- Absolute child with left positioning (reserves left space)
|
||||
FlexLove.new({
|
||||
id = "absolute_left",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
left = 0,
|
||||
top = 0,
|
||||
width = 50,
|
||||
height = 50
|
||||
})
|
||||
|
||||
-- Regular grid child
|
||||
local child1 = FlexLove.new({
|
||||
id = "child1",
|
||||
parent = container,
|
||||
width = 50,
|
||||
height = 50
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Grid should account for reserved space
|
||||
-- Available width: 400 - 50 (reserved left) = 350
|
||||
-- Cell width: 350 / 2 = 175
|
||||
-- Child should start at x = reserved left = 50
|
||||
luaunit.assertEquals(child1.x, 50, "Child should be offset by reserved left space")
|
||||
luaunit.assertEquals(child1.width, 175, "Cell width should account for reserved space")
|
||||
end
|
||||
|
||||
if not _G.RUNNING_ALL_TESTS then
|
||||
os.exit(luaunit.LuaUnit.run())
|
||||
end
|
||||
404
testing/__tests__/layout_edge_cases_test.lua
Normal file
404
testing/__tests__/layout_edge_cases_test.lua
Normal file
@@ -0,0 +1,404 @@
|
||||
-- Test suite for layout edge cases and warnings
|
||||
-- Tests untested code paths in LayoutEngine
|
||||
package.path = package.path .. ";./?.lua;./modules/?.lua"
|
||||
|
||||
require("testing.loveStub")
|
||||
local luaunit = require("testing.luaunit")
|
||||
local FlexLove = require("FlexLove")
|
||||
local ErrorHandler = require("modules.ErrorHandler")
|
||||
|
||||
TestLayoutEdgeCases = {}
|
||||
|
||||
function TestLayoutEdgeCases:setUp()
|
||||
FlexLove.setMode("immediate")
|
||||
FlexLove.beginFrame()
|
||||
-- Capture warnings
|
||||
self.warnings = {}
|
||||
self.originalWarn = ErrorHandler.warn
|
||||
ErrorHandler.warn = function(module, message)
|
||||
table.insert(self.warnings, {module = module, message = message})
|
||||
end
|
||||
end
|
||||
|
||||
function TestLayoutEdgeCases:tearDown()
|
||||
-- Restore original warn function
|
||||
ErrorHandler.warn = self.originalWarn
|
||||
FlexLove.endFrame()
|
||||
end
|
||||
|
||||
-- Test: Child with percentage width in auto-sizing parent should trigger warning
|
||||
function TestLayoutEdgeCases:test_percentage_width_with_auto_parent_warns()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
-- width not specified - auto-sizing width
|
||||
height = 200,
|
||||
positioning = "flex",
|
||||
flexDirection = "horizontal"
|
||||
})
|
||||
|
||||
FlexLove.new({
|
||||
id = "child_with_percentage",
|
||||
parent = container,
|
||||
width = "50%", -- Percentage width with auto-sizing parent - should warn
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Check that a warning was issued
|
||||
luaunit.assertTrue(#self.warnings > 0, "Should issue warning for percentage width with auto-sizing parent")
|
||||
|
||||
local found = false
|
||||
for _, warning in ipairs(self.warnings) do
|
||||
if warning.message:match("percentage width") and warning.message:match("auto%-sizing") then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
luaunit.assertTrue(found, "Warning should mention percentage width and auto-sizing")
|
||||
end
|
||||
|
||||
-- Test: Child with percentage height in auto-sizing parent should trigger warning
|
||||
function TestLayoutEdgeCases:test_percentage_height_with_auto_parent_warns()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
-- height not specified - auto-sizing height
|
||||
positioning = "flex",
|
||||
flexDirection = "vertical"
|
||||
})
|
||||
|
||||
FlexLove.new({
|
||||
id = "child_with_percentage",
|
||||
parent = container,
|
||||
width = 100,
|
||||
height = "50%" -- Percentage height with auto-sizing parent - should warn
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Check that a warning was issued
|
||||
luaunit.assertTrue(#self.warnings > 0, "Should issue warning for percentage height with auto-sizing parent")
|
||||
|
||||
local found = false
|
||||
for _, warning in ipairs(self.warnings) do
|
||||
if warning.message:match("percentage height") and warning.message:match("auto%-sizing") then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
luaunit.assertTrue(found, "Warning should mention percentage height and auto-sizing")
|
||||
end
|
||||
|
||||
-- Test: Pixel-sized children in auto-sizing parent should NOT warn
|
||||
function TestLayoutEdgeCases:test_pixel_width_with_auto_parent_no_warn()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
-- width not specified - auto-sizing
|
||||
height = 200,
|
||||
positioning = "flex",
|
||||
flexDirection = "horizontal"
|
||||
})
|
||||
|
||||
FlexLove.new({
|
||||
id = "child_with_pixels",
|
||||
parent = container,
|
||||
width = 100, -- Pixel width - should NOT warn
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Check that NO warning was issued about percentage sizing
|
||||
for _, warning in ipairs(self.warnings) do
|
||||
local hasPercentageWarning = warning.message:match("percentage") and warning.message:match("auto%-sizing")
|
||||
luaunit.assertFalse(hasPercentageWarning, "Should not warn for pixel-sized children")
|
||||
end
|
||||
end
|
||||
|
||||
-- Test: CSS positioning - top offset in absolute container
|
||||
function TestLayoutEdgeCases:test_css_positioning_top_offset()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 100,
|
||||
y = 100,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "absolute"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 50, -- 50px from top
|
||||
left = 0,
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
-- Trigger layout by ending and restarting frame
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Child should be positioned 50px from container's top edge (accounting for padding)
|
||||
local expectedY = container.y + container.padding.top + 50
|
||||
luaunit.assertEquals(child.y, expectedY, "Child should be positioned with top offset")
|
||||
end
|
||||
|
||||
-- Test: CSS positioning - bottom offset in absolute container
|
||||
function TestLayoutEdgeCases:test_css_positioning_bottom_offset()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 100,
|
||||
y = 100,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "absolute"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
bottom = 50, -- 50px from bottom
|
||||
left = 0,
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Child should be positioned 50px from container's bottom edge
|
||||
local expectedY = container.y + container.padding.top + container.height - 50 - child:getBorderBoxHeight()
|
||||
luaunit.assertEquals(child.y, expectedY, "Child should be positioned with bottom offset")
|
||||
end
|
||||
|
||||
-- Test: CSS positioning - left offset in absolute container
|
||||
function TestLayoutEdgeCases:test_css_positioning_left_offset()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 100,
|
||||
y = 100,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "absolute"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 0,
|
||||
left = 50, -- 50px from left
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Child should be positioned 50px from container's left edge
|
||||
local expectedX = container.x + container.padding.left + 50
|
||||
luaunit.assertEquals(child.x, expectedX, "Child should be positioned with left offset")
|
||||
end
|
||||
|
||||
-- Test: CSS positioning - right offset in absolute container
|
||||
function TestLayoutEdgeCases:test_css_positioning_right_offset()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 100,
|
||||
y = 100,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "absolute"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 0,
|
||||
right = 50, -- 50px from right
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Child should be positioned 50px from container's right edge
|
||||
local expectedX = container.x + container.padding.left + container.width - 50 - child:getBorderBoxWidth()
|
||||
luaunit.assertEquals(child.x, expectedX, "Child should be positioned with right offset")
|
||||
end
|
||||
|
||||
-- Test: CSS positioning - combined top and bottom (bottom should take precedence or be ignored)
|
||||
function TestLayoutEdgeCases:test_css_positioning_top_and_bottom()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 100,
|
||||
y = 100,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "absolute"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 10,
|
||||
bottom = 20, -- Both specified - last one wins in current implementation
|
||||
left = 0,
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Bottom should override top
|
||||
local expectedY = container.y + container.padding.top + container.height - 20 - child:getBorderBoxHeight()
|
||||
luaunit.assertEquals(child.y, expectedY, "Bottom offset should override top when both specified")
|
||||
end
|
||||
|
||||
-- Test: CSS positioning - combined left and right (right should take precedence or be ignored)
|
||||
function TestLayoutEdgeCases:test_css_positioning_left_and_right()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 100,
|
||||
y = 100,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "absolute"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 0,
|
||||
left = 10,
|
||||
right = 20, -- Both specified - last one wins in current implementation
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Right should override left
|
||||
local expectedX = container.x + container.padding.left + container.width - 20 - child:getBorderBoxWidth()
|
||||
luaunit.assertEquals(child.x, expectedX, "Right offset should override left when both specified")
|
||||
end
|
||||
|
||||
-- Test: CSS positioning with padding in container
|
||||
function TestLayoutEdgeCases:test_css_positioning_with_padding()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 100,
|
||||
y = 100,
|
||||
width = 400,
|
||||
height = 400,
|
||||
padding = { top = 20, right = 20, bottom = 20, left = 20 },
|
||||
positioning = "absolute"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 10,
|
||||
left = 10,
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Offsets should be relative to content area (after padding)
|
||||
local expectedX = container.x + container.padding.left + 10
|
||||
local expectedY = container.y + container.padding.top + 10
|
||||
|
||||
luaunit.assertEquals(child.x, expectedX, "Left offset should account for container padding")
|
||||
luaunit.assertEquals(child.y, expectedY, "Top offset should account for container padding")
|
||||
end
|
||||
|
||||
-- Test: CSS positioning should NOT affect flex children
|
||||
function TestLayoutEdgeCases:test_css_positioning_ignored_in_flex()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "flex",
|
||||
flexDirection = "horizontal"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
top = 100, -- This should be IGNORED in flex layout
|
||||
left = 100, -- This should be IGNORED in flex layout
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- In flex layout, child should be positioned by flex rules, not CSS offsets
|
||||
-- Child should be at (0, 0) relative to container content area
|
||||
luaunit.assertEquals(child.x, 0, "CSS offsets should be ignored in flex layout")
|
||||
luaunit.assertEquals(child.y, 0, "CSS offsets should be ignored in flex layout")
|
||||
end
|
||||
|
||||
-- Test: CSS positioning in relative container
|
||||
function TestLayoutEdgeCases:test_css_positioning_in_relative_container()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 100,
|
||||
y = 100,
|
||||
width = 400,
|
||||
height = 400,
|
||||
positioning = "relative"
|
||||
})
|
||||
|
||||
local child = FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 30,
|
||||
left = 30,
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame()
|
||||
|
||||
-- Should work the same as absolute container
|
||||
local expectedX = container.x + container.padding.left + 30
|
||||
local expectedY = container.y + container.padding.top + 30
|
||||
|
||||
luaunit.assertEquals(child.x, expectedX, "CSS positioning should work in relative containers")
|
||||
luaunit.assertEquals(child.y, expectedY, "CSS positioning should work in relative containers")
|
||||
end
|
||||
|
||||
if not _G.RUNNING_ALL_TESTS then
|
||||
os.exit(luaunit.LuaUnit.run())
|
||||
end
|
||||
345
testing/__tests__/overflow_test.lua
Normal file
345
testing/__tests__/overflow_test.lua
Normal file
@@ -0,0 +1,345 @@
|
||||
-- Test suite for overflow detection and scroll behavior
|
||||
-- This tests the critical ScrollManager.detectOverflow() path which is currently 0% covered
|
||||
package.path = package.path .. ";./?.lua;./modules/?.lua"
|
||||
|
||||
require("testing.loveStub")
|
||||
local luaunit = require("testing.luaunit")
|
||||
local FlexLove = require("FlexLove")
|
||||
|
||||
TestOverflowDetection = {}
|
||||
|
||||
function TestOverflowDetection:setUp()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
end
|
||||
|
||||
function TestOverflowDetection:tearDown()
|
||||
FlexLove.endFrame()
|
||||
end
|
||||
|
||||
-- Test basic overflow detection when content exceeds container
|
||||
function TestOverflowDetection:test_vertical_overflow_detected()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 100,
|
||||
overflow = "scroll"
|
||||
})
|
||||
|
||||
-- Add child that exceeds container height
|
||||
FlexLove.new({
|
||||
id = "tall_child",
|
||||
parent = container,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 100,
|
||||
height = 200 -- Taller than container (100)
|
||||
})
|
||||
|
||||
-- Force layout to trigger detectOverflow
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Check if overflow was detected
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
luaunit.assertTrue(maxScrollY > 0, "Should detect vertical overflow")
|
||||
luaunit.assertEquals(maxScrollX, 0, "Should not have horizontal overflow")
|
||||
end
|
||||
|
||||
function TestOverflowDetection:test_horizontal_overflow_detected()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 100,
|
||||
height = 200,
|
||||
overflow = "scroll"
|
||||
})
|
||||
|
||||
-- Add child that exceeds container width
|
||||
FlexLove.new({
|
||||
id = "wide_child",
|
||||
parent = container,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 300, -- Wider than container (100)
|
||||
height = 50
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
luaunit.assertTrue(maxScrollX > 0, "Should detect horizontal overflow")
|
||||
luaunit.assertEquals(maxScrollY, 0, "Should not have vertical overflow")
|
||||
end
|
||||
|
||||
function TestOverflowDetection:test_both_axes_overflow()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 100,
|
||||
height = 100,
|
||||
overflow = "scroll"
|
||||
})
|
||||
|
||||
-- Add child that exceeds both dimensions
|
||||
FlexLove.new({
|
||||
id = "large_child",
|
||||
parent = container,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 200
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
luaunit.assertTrue(maxScrollX > 0, "Should detect horizontal overflow")
|
||||
luaunit.assertTrue(maxScrollY > 0, "Should detect vertical overflow")
|
||||
end
|
||||
|
||||
function TestOverflowDetection:test_no_overflow_when_content_fits()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 200,
|
||||
overflow = "scroll"
|
||||
})
|
||||
|
||||
-- Add child that fits within container
|
||||
FlexLove.new({
|
||||
id = "small_child",
|
||||
parent = container,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 100,
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
luaunit.assertEquals(maxScrollX, 0, "Should not have horizontal overflow")
|
||||
luaunit.assertEquals(maxScrollY, 0, "Should not have vertical overflow")
|
||||
end
|
||||
|
||||
function TestOverflowDetection:test_overflow_with_multiple_children()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 200,
|
||||
overflow = "scroll",
|
||||
positioning = "flex",
|
||||
flexDirection = "vertical"
|
||||
})
|
||||
|
||||
-- Add multiple children that together exceed container
|
||||
for i = 1, 5 do
|
||||
FlexLove.new({
|
||||
id = "child_" .. i,
|
||||
parent = container,
|
||||
width = 150,
|
||||
height = 60 -- 5 * 60 = 300, exceeds container height of 200
|
||||
})
|
||||
end
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
luaunit.assertTrue(maxScrollY > 0, "Should detect overflow from multiple children")
|
||||
end
|
||||
|
||||
function TestOverflowDetection:test_overflow_with_padding()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 200,
|
||||
padding = { top = 10, right = 10, bottom = 10, left = 10 },
|
||||
overflow = "scroll"
|
||||
})
|
||||
|
||||
-- Child that fits in container but exceeds available content area (200 - 20 = 180)
|
||||
FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 190, -- Exceeds content width (180)
|
||||
height = 100
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
luaunit.assertTrue(maxScrollX > 0, "Should detect overflow accounting for padding")
|
||||
end
|
||||
|
||||
function TestOverflowDetection:test_overflow_with_margins()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 200,
|
||||
positioning = "flex",
|
||||
flexDirection = "horizontal",
|
||||
overflow = "scroll"
|
||||
})
|
||||
|
||||
-- Child with margins that contribute to overflow
|
||||
-- In flex layout, margins are properly accounted for in positioning
|
||||
FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
width = 180,
|
||||
height = 180,
|
||||
margin = { top = 5, right = 20, bottom = 5, left = 5 } -- Total width: 5+180+20=205, overflows 200px container
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
luaunit.assertTrue(maxScrollX > 0, "Should include child margins in overflow calculation")
|
||||
end
|
||||
|
||||
-- Test edge case: overflow = "visible" should skip detection
|
||||
function TestOverflowDetection:test_visible_overflow_skips_detection()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 100,
|
||||
height = 100,
|
||||
overflow = "visible" -- Should not clip or calculate overflow
|
||||
})
|
||||
|
||||
-- Add oversized child
|
||||
FlexLove.new({
|
||||
id = "large_child",
|
||||
parent = container,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 300,
|
||||
height = 300
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- With overflow="visible", maxScroll should be 0 (no scrolling)
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
luaunit.assertEquals(maxScrollX, 0, "visible overflow should not enable scrolling")
|
||||
luaunit.assertEquals(maxScrollY, 0, "visible overflow should not enable scrolling")
|
||||
end
|
||||
|
||||
-- Test edge case: empty container
|
||||
function TestOverflowDetection:test_empty_container_no_overflow()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 200,
|
||||
overflow = "scroll"
|
||||
-- No children
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
luaunit.assertEquals(maxScrollX, 0, "Empty container should have no overflow")
|
||||
luaunit.assertEquals(maxScrollY, 0, "Empty container should have no overflow")
|
||||
end
|
||||
|
||||
-- Test overflow with absolutely positioned children (should be ignored)
|
||||
function TestOverflowDetection:test_absolute_children_ignored_in_overflow()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 200,
|
||||
height = 200,
|
||||
overflow = "scroll"
|
||||
})
|
||||
|
||||
-- Regular child that fits
|
||||
FlexLove.new({
|
||||
id = "normal_child",
|
||||
parent = container,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 150,
|
||||
height = 150
|
||||
})
|
||||
|
||||
-- Absolutely positioned child that extends beyond (should NOT cause overflow)
|
||||
FlexLove.new({
|
||||
id = "absolute_child",
|
||||
parent = container,
|
||||
positioning = "absolute",
|
||||
top = 0,
|
||||
left = 0,
|
||||
width = 400,
|
||||
height = 400
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
-- Should not have overflow because absolute children are ignored
|
||||
luaunit.assertEquals(maxScrollX, 0, "Absolute children should not cause overflow")
|
||||
luaunit.assertEquals(maxScrollY, 0, "Absolute children should not cause overflow")
|
||||
end
|
||||
|
||||
-- Test scroll clamping with overflow
|
||||
function TestOverflowDetection:test_scroll_clamped_to_max()
|
||||
local container = FlexLove.new({
|
||||
id = "container",
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 100,
|
||||
height = 100,
|
||||
overflow = "scroll"
|
||||
})
|
||||
|
||||
FlexLove.new({
|
||||
id = "child",
|
||||
parent = container,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = 100,
|
||||
height = 300 -- Creates 200px of vertical overflow
|
||||
})
|
||||
|
||||
FlexLove.endFrame()
|
||||
FlexLove.beginFrame(1920, 1080)
|
||||
|
||||
-- Try to scroll beyond max
|
||||
container:setScrollPosition(0, 999999)
|
||||
local scrollX, scrollY = container:getScrollPosition()
|
||||
local maxScrollX, maxScrollY = container:getMaxScroll()
|
||||
|
||||
luaunit.assertEquals(scrollY, maxScrollY, "Scroll should be clamped to maximum")
|
||||
luaunit.assertTrue(scrollY < 999999, "Should not scroll beyond content")
|
||||
end
|
||||
|
||||
if not _G.RUNNING_ALL_TESTS then
|
||||
os.exit(luaunit.LuaUnit.run())
|
||||
end
|
||||
@@ -25,6 +25,9 @@ local testFiles = {
|
||||
"testing/__tests__/theme_test.lua",
|
||||
"testing/__tests__/layout_engine_test.lua",
|
||||
"testing/__tests__/element_test.lua",
|
||||
"testing/__tests__/overflow_test.lua",
|
||||
"testing/__tests__/grid_test.lua",
|
||||
"testing/__tests__/layout_edge_cases_test.lua",
|
||||
}
|
||||
|
||||
local success = true
|
||||
|
||||
Reference in New Issue
Block a user