408 lines
10 KiB
Lua
408 lines
10 KiB
Lua
-- Test retained children persisting when immediate parents recreate
|
|
package.path = package.path .. ";./?.lua;./modules/?.lua"
|
|
local originalSearchers = package.searchers or package.loaders
|
|
table.insert(originalSearchers, 2, function(modname)
|
|
if modname:match("^FlexLove%.modules%.") then
|
|
local moduleName = modname:gsub("^FlexLove%.modules%.", "")
|
|
return function()
|
|
return require("modules." .. moduleName)
|
|
end
|
|
end
|
|
end)
|
|
|
|
require("testing.loveStub")
|
|
local luaunit = require("testing.luaunit")
|
|
local FlexLove = require("FlexLove")
|
|
|
|
TestMixedModeChildren = {}
|
|
|
|
function TestMixedModeChildren:setUp()
|
|
FlexLove.init({ immediateMode = true })
|
|
FlexLove.setMode("immediate")
|
|
end
|
|
|
|
function TestMixedModeChildren:tearDown()
|
|
FlexLove._defaultDependencies.StateManager.reset()
|
|
FlexLove.topElements = {}
|
|
FlexLove._currentFrameElements = {}
|
|
FlexLove._frameStarted = false
|
|
end
|
|
|
|
-- Test 1: Retained child persists when immediate parent recreates
|
|
function TestMixedModeChildren:testRetainedChildPersistsWithImmediateParent()
|
|
FlexLove.beginFrame()
|
|
|
|
-- Frame 1: Create immediate parent with retained child
|
|
local parent1 = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
local retainedChild = FlexLove.new({
|
|
id = "retained_child",
|
|
mode = "retained",
|
|
width = 50,
|
|
height = 50,
|
|
})
|
|
|
|
parent1:addChild(retainedChild)
|
|
|
|
luaunit.assertEquals(#parent1.children, 1, "Parent should have 1 child")
|
|
luaunit.assertEquals(parent1.children[1], retainedChild, "Child should be the retained element")
|
|
luaunit.assertEquals(retainedChild.parent, parent1, "Child's parent should be set")
|
|
|
|
FlexLove.endFrame()
|
|
|
|
-- Frame 2: Recreate immediate parent, retained child should persist
|
|
FlexLove.beginFrame()
|
|
|
|
local parent2 = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
-- The retained child should be automatically restored
|
|
luaunit.assertEquals(#parent2.children, 1, "Parent should still have 1 child after recreation")
|
|
luaunit.assertEquals(parent2.children[1], retainedChild, "Child should be the same retained element")
|
|
luaunit.assertEquals(retainedChild.parent, parent2, "Child's parent reference should be updated")
|
|
|
|
FlexLove.endFrame()
|
|
end
|
|
|
|
-- Test 2: Multiple retained children persist
|
|
function TestMixedModeChildren:testMultipleRetainedChildrenPersist()
|
|
FlexLove.beginFrame()
|
|
|
|
local parent1 = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
local child1 = FlexLove.new({
|
|
id = "child1",
|
|
mode = "retained",
|
|
width = 50,
|
|
height = 50,
|
|
})
|
|
|
|
local child2 = FlexLove.new({
|
|
id = "child2",
|
|
mode = "retained",
|
|
width = 50,
|
|
height = 50,
|
|
})
|
|
|
|
local child3 = FlexLove.new({
|
|
id = "child3",
|
|
mode = "retained",
|
|
width = 50,
|
|
height = 50,
|
|
})
|
|
|
|
parent1:addChild(child1)
|
|
parent1:addChild(child2)
|
|
parent1:addChild(child3)
|
|
|
|
luaunit.assertEquals(#parent1.children, 3, "Parent should have 3 children")
|
|
|
|
FlexLove.endFrame()
|
|
|
|
-- Frame 2
|
|
FlexLove.beginFrame()
|
|
|
|
local parent2 = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
luaunit.assertEquals(#parent2.children, 3, "Parent should still have 3 children")
|
|
luaunit.assertEquals(parent2.children[1], child1, "First child should persist")
|
|
luaunit.assertEquals(parent2.children[2], child2, "Second child should persist")
|
|
luaunit.assertEquals(parent2.children[3], child3, "Third child should persist")
|
|
|
|
FlexLove.endFrame()
|
|
end
|
|
|
|
-- Test 3: Immediate children do NOT persist (only retained children)
|
|
function TestMixedModeChildren:testImmediateChildrenDoNotPersist()
|
|
FlexLove.beginFrame()
|
|
|
|
local parent1 = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
local immediateChild = FlexLove.new({
|
|
id = "immediate_child",
|
|
mode = "immediate",
|
|
width = 50,
|
|
height = 50,
|
|
})
|
|
|
|
local retainedChild = FlexLove.new({
|
|
id = "retained_child",
|
|
mode = "retained",
|
|
width = 50,
|
|
height = 50,
|
|
})
|
|
|
|
parent1:addChild(immediateChild)
|
|
parent1:addChild(retainedChild)
|
|
|
|
luaunit.assertEquals(#parent1.children, 2, "Parent should have 2 children")
|
|
|
|
FlexLove.endFrame()
|
|
|
|
-- Frame 2
|
|
FlexLove.beginFrame()
|
|
|
|
local parent2 = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
-- Only retained child should persist
|
|
luaunit.assertEquals(#parent2.children, 1, "Parent should only have 1 child (retained)")
|
|
luaunit.assertEquals(parent2.children[1], retainedChild, "Only retained child should persist")
|
|
|
|
FlexLove.endFrame()
|
|
end
|
|
|
|
-- Test 4: Top-level retained element persists in immediate mode
|
|
function TestMixedModeChildren:testTopLevelRetainedElementPersists()
|
|
FlexLove.beginFrame()
|
|
|
|
local retainedElement = FlexLove.new({
|
|
id = "top_retained",
|
|
mode = "retained",
|
|
width = 100,
|
|
height = 100,
|
|
})
|
|
|
|
luaunit.assertEquals(#FlexLove.topElements, 1, "Should have 1 top-level element")
|
|
luaunit.assertEquals(FlexLove.topElements[1], retainedElement, "Top element should be retained element")
|
|
|
|
FlexLove.endFrame()
|
|
|
|
-- Frame 2
|
|
FlexLove.beginFrame()
|
|
|
|
-- Retained element should still be in topElements
|
|
luaunit.assertEquals(#FlexLove.topElements, 1, "Retained element should persist in topElements")
|
|
luaunit.assertEquals(FlexLove.topElements[1], retainedElement, "Should be same retained element")
|
|
|
|
FlexLove.endFrame()
|
|
end
|
|
|
|
-- Test 5: Mixed top-level elements (immediate and retained)
|
|
function TestMixedModeChildren:testMixedTopLevelElements()
|
|
FlexLove.beginFrame()
|
|
|
|
local immediateElement1 = FlexLove.new({
|
|
id = "immediate1",
|
|
mode = "immediate",
|
|
width = 100,
|
|
height = 100,
|
|
})
|
|
|
|
local retainedElement = FlexLove.new({
|
|
id = "retained",
|
|
mode = "retained",
|
|
width = 100,
|
|
height = 100,
|
|
})
|
|
|
|
luaunit.assertEquals(#FlexLove.topElements, 2, "Should have 2 top-level elements")
|
|
|
|
FlexLove.endFrame()
|
|
|
|
-- Frame 2
|
|
FlexLove.beginFrame()
|
|
|
|
local immediateElement2 = FlexLove.new({
|
|
id = "immediate2",
|
|
mode = "immediate",
|
|
width = 100,
|
|
height = 100,
|
|
})
|
|
|
|
-- Should have retained element + new immediate element
|
|
luaunit.assertEquals(#FlexLove.topElements, 2, "Should have 2 top-level elements")
|
|
|
|
-- Find retained element in topElements
|
|
local foundRetained = false
|
|
for _, elem in ipairs(FlexLove.topElements) do
|
|
if elem == retainedElement then
|
|
foundRetained = true
|
|
break
|
|
end
|
|
end
|
|
|
|
luaunit.assertTrue(foundRetained, "Retained element should still be in topElements")
|
|
|
|
FlexLove.endFrame()
|
|
end
|
|
|
|
-- Test 6: Retained child cleanup on parent destroy
|
|
function TestMixedModeChildren:testRetainedChildCleanupOnDestroy()
|
|
FlexLove.beginFrame()
|
|
|
|
local parent = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
local retainedChild = FlexLove.new({
|
|
id = "retained_child",
|
|
mode = "retained",
|
|
width = 50,
|
|
height = 50,
|
|
})
|
|
|
|
parent:addChild(retainedChild)
|
|
|
|
FlexLove.endFrame()
|
|
|
|
-- Destroy parent (simulating explicit cleanup)
|
|
parent:destroy()
|
|
|
|
-- Frame 2: Create new parent with same ID
|
|
FlexLove.beginFrame()
|
|
|
|
local parent2 = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
-- Since parent was destroyed, retained children should be cleared
|
|
luaunit.assertEquals(#parent2.children, 0, "Parent should have no children after destroy")
|
|
|
|
FlexLove.endFrame()
|
|
end
|
|
|
|
-- Test 7: Nested mixed-mode tree (immediate -> retained -> immediate)
|
|
function TestMixedModeChildren:testNestedMixedModeTree()
|
|
FlexLove.beginFrame()
|
|
|
|
local immediateParent = FlexLove.new({
|
|
id = "immediate_parent",
|
|
mode = "immediate",
|
|
width = 300,
|
|
height = 300,
|
|
})
|
|
|
|
local retainedMiddle = FlexLove.new({
|
|
id = "retained_middle",
|
|
mode = "retained",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
local immediateGrandchild = FlexLove.new({
|
|
id = "immediate_grandchild",
|
|
mode = "immediate",
|
|
width = 100,
|
|
height = 100,
|
|
})
|
|
|
|
immediateParent:addChild(retainedMiddle)
|
|
retainedMiddle:addChild(immediateGrandchild)
|
|
|
|
luaunit.assertEquals(#immediateParent.children, 1, "Immediate parent should have 1 child")
|
|
luaunit.assertEquals(#retainedMiddle.children, 1, "Retained middle should have 1 child")
|
|
|
|
FlexLove.endFrame()
|
|
|
|
-- Frame 2: Recreate immediate parent
|
|
FlexLove.beginFrame()
|
|
|
|
local immediateParent2 = FlexLove.new({
|
|
id = "immediate_parent",
|
|
mode = "immediate",
|
|
width = 300,
|
|
height = 300,
|
|
})
|
|
|
|
-- Retained middle should persist
|
|
luaunit.assertEquals(#immediateParent2.children, 1, "Immediate parent should still have retained child")
|
|
luaunit.assertEquals(immediateParent2.children[1], retainedMiddle, "Retained middle should persist")
|
|
|
|
-- Immediate grandchild should also persist (as child of retained middle)
|
|
luaunit.assertEquals(#retainedMiddle.children, 1, "Retained middle should still have its child")
|
|
|
|
FlexLove.endFrame()
|
|
end
|
|
|
|
-- Test 8: Prevent duplicate creation of retained children
|
|
function TestMixedModeChildren:testPreventDuplicateRetainedChildren()
|
|
FlexLove.beginFrame()
|
|
|
|
-- Frame 1: Create immediate parent with retained child
|
|
local parent1 = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
local retainedChild = FlexLove.new({
|
|
id = "unique_child",
|
|
mode = "retained",
|
|
parent = parent1,
|
|
width = 50,
|
|
height = 50,
|
|
})
|
|
|
|
luaunit.assertEquals(#parent1.children, 1, "Parent should have 1 child")
|
|
local originalChild = parent1.children[1]
|
|
|
|
FlexLove.endFrame()
|
|
|
|
-- Frame 2: Recreate parent and try to create child again
|
|
FlexLove.beginFrame()
|
|
|
|
local parent2 = FlexLove.new({
|
|
id = "parent",
|
|
mode = "immediate",
|
|
width = 200,
|
|
height = 200,
|
|
})
|
|
|
|
-- Try to create the same retained child again
|
|
local duplicateAttempt = FlexLove.new({
|
|
id = "unique_child",
|
|
mode = "retained",
|
|
parent = parent2,
|
|
width = 50,
|
|
height = 50,
|
|
})
|
|
|
|
-- Should return the existing child, not create a new one
|
|
luaunit.assertEquals(duplicateAttempt, originalChild, "Should return existing child instead of creating duplicate")
|
|
luaunit.assertEquals(duplicateAttempt, retainedChild, "Should be the same retained child instance")
|
|
luaunit.assertEquals(#parent2.children, 1, "Parent should still have only 1 child")
|
|
|
|
FlexLove.endFrame()
|
|
end
|
|
|
|
-- Run tests
|
|
if not _G.RUNNING_ALL_TESTS then
|
|
os.exit(luaunit.LuaUnit.run())
|
|
end
|