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 local Positioning = enums.Positioning local FlexDirection = enums.FlexDirection local JustifyContent = enums.JustifyContent local AlignItems = enums.AlignItems local FlexWrap = enums.FlexWrap -- Create test cases for performance testing TestPerformance = {} function TestPerformance:setUp() -- Clean up before each test Gui.destroy() end function TestPerformance:tearDown() -- Clean up after each test Gui.destroy() end -- Helper function to measure execution time local function measureTime(func) local start_time = os.clock() local result = func() local end_time = os.clock() return end_time - start_time, result end -- Helper function to create test containers local function createTestContainer(props) props = props or {} local defaults = { x = 0, y = 0, w = 800, h = 600, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.FLEX_START, alignItems = AlignItems.STRETCH, flexWrap = FlexWrap.NOWRAP, gap = 0, } for key, value in pairs(props) do defaults[key] = value end return Gui.new(defaults) end -- Helper function to create many children local function createManyChildren(parent, count, child_props) child_props = child_props or {} local children = {} for i = 1, count do local props = { w = child_props.w or 50, h = child_props.h or 30, } -- Add any additional properties for key, value in pairs(child_props) do if key ~= "w" and key ~= "h" then props[key] = value end end local child = Gui.new(props) child.parent = parent table.insert(parent.children, child) table.insert(children, child) end return children end -- Test 1: Basic Layout Performance Benchmark function TestPerformance:testBasicLayoutPerformanceBenchmark() local container = createTestContainer() -- Test with small number of children (baseline) local children_10 = createManyChildren(container, 10) local time_10, _ = measureTime(function() container:layoutChildren() end) -- Clear and test with medium number of children container.children = {} local children_50 = createManyChildren(container, 50) local time_50, _ = measureTime(function() container:layoutChildren() end) -- Clear and test with larger number of children container.children = {} local children_100 = createManyChildren(container, 100) local time_100, _ = measureTime(function() container:layoutChildren() end) print(string.format("Performance Benchmark:")) print(string.format(" 10 children: %.6f seconds", time_10)) print(string.format(" 50 children: %.6f seconds", time_50)) print(string.format(" 100 children: %.6f seconds", time_100)) -- Assert reasonable performance (should complete within 1 second) luaunit.assertTrue(time_10 < 1.0, "10 children layout should complete within 1 second") luaunit.assertTrue(time_50 < 1.0, "50 children layout should complete within 1 second") luaunit.assertTrue(time_100 < 1.0, "100 children layout should complete within 1 second") -- Performance should scale reasonably (not exponentially) -- Allow some overhead but ensure it's not exponential growth luaunit.assertTrue(time_100 <= time_10 * 50, "Performance should not degrade exponentially") end -- Test 2: Scalability Testing with Large Numbers function TestPerformance:testScalabilityWithLargeNumbers() local container = createTestContainer() -- Test progressively larger numbers of children local test_sizes = { 10, 50, 100, 200 } local times = {} for _, size in ipairs(test_sizes) do container.children = {} -- Clear previous children local children = createManyChildren(container, size) local time, _ = measureTime(function() container:layoutChildren() end) times[size] = time print(string.format("Scalability Test - %d children: %.6f seconds", size, time)) -- Each test should complete within reasonable time luaunit.assertTrue(time < 2.0, string.format("%d children should layout within 2 seconds", size)) end -- Check that performance scales linearly or sub-linearly -- Time for 200 children should not be more than 20x time for 10 children luaunit.assertTrue(times[200] <= times[10] * 20, "Performance should scale sub-linearly") end -- Test 3: Complex Nested Layout Performance function TestPerformance:testComplexNestedLayoutPerformance() -- Create a deeply nested structure with multiple levels local root = createTestContainer({ w = 1000, h = 800, flexDirection = FlexDirection.VERTICAL, }) local time, _ = measureTime(function() -- Level 1: 5 sections for i = 1, 5 do local section = Gui.new({ w = 950, h = 150, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_BETWEEN, }) section.parent = root table.insert(root.children, section) -- Level 2: 4 columns per section for j = 1, 4 do local column = Gui.new({ w = 200, h = 140, positioning = Positioning.FLEX, flexDirection = FlexDirection.VERTICAL, alignItems = AlignItems.CENTER, }) column.parent = section table.insert(section.children, column) -- Level 3: 3 items per column for k = 1, 3 do local item = Gui.new({ w = 180, h = 40, }) item.parent = column table.insert(column.children, item) end end end -- Layout the entire structure root:layoutChildren() end) print(string.format("Complex Nested Layout (5x4x3 = 60 total elements): %.6f seconds", time)) -- Complex nested layout should complete within reasonable time luaunit.assertTrue(time < 3.0, "Complex nested layout should complete within 3 seconds") -- Verify structure was created correctly luaunit.assertEquals(#root.children, 5) -- 5 sections luaunit.assertEquals(#root.children[1].children, 4) -- 4 columns per section luaunit.assertEquals(#root.children[1].children[1].children, 3) -- 3 items per column end -- Test 4: Flex Wrap Performance with Many Elements function TestPerformance:testFlexWrapPerformanceWithManyElements() local container = createTestContainer({ w = 400, h = 600, flexDirection = FlexDirection.HORIZONTAL, flexWrap = FlexWrap.WRAP, justifyContent = JustifyContent.SPACE_AROUND, alignItems = AlignItems.CENTER, }) -- Create many children that will wrap local children = createManyChildren(container, 50, { w = 80, h = 50, }) local time, _ = measureTime(function() container:layoutChildren() end) print(string.format("Flex Wrap Performance (50 wrapping elements): %.6f seconds", time)) -- Flex wrap with many elements should complete within reasonable time luaunit.assertTrue(time < 2.0, "Flex wrap layout should complete within 2 seconds") -- Verify that elements are positioned (wrapped layout worked) luaunit.assertTrue(children[1].x >= 0 and children[1].y >= 0, "First child should be positioned") luaunit.assertTrue(children[#children].x >= 0 and children[#children].y >= 0, "Last child should be positioned") end -- Test 5: Dynamic Layout Change Performance function TestPerformance:testDynamicLayoutChangePerformance() local container = createTestContainer() local children = createManyChildren(container, 30) -- Initial layout container:layoutChildren() -- Test performance of multiple layout property changes local time, _ = measureTime(function() for i = 1, 10 do -- Change flex direction container.flexDirection = (i % 2 == 0) and FlexDirection.VERTICAL or FlexDirection.HORIZONTAL container:layoutChildren() -- Change justify content container.justifyContent = (i % 3 == 0) and JustifyContent.CENTER or JustifyContent.FLEX_START container:layoutChildren() -- Change align items container.alignItems = (i % 4 == 0) and AlignItems.CENTER or AlignItems.STRETCH container:layoutChildren() end end) print(string.format("Dynamic Layout Changes (30 relayouts): %.6f seconds", time)) -- Dynamic layout changes should complete within reasonable time luaunit.assertTrue(time < 2.0, "Dynamic layout changes should complete within 2 seconds") -- Verify final layout is valid luaunit.assertTrue(children[1].x >= 0 and children[1].y >= 0, "Children should be positioned after changes") end -- Test 6: Memory Usage Pattern Test function TestPerformance:testMemoryUsagePattern() -- This test checks that we don't have obvious memory leaks during layout operations local container = createTestContainer() -- Create and destroy many children multiple times local time, _ = measureTime(function() for cycle = 1, 5 do -- Create children local children = createManyChildren(container, 100) container:layoutChildren() -- Clear children (simulating component cleanup) container.children = {} -- Force garbage collection to test for leaks collectgarbage("collect") end end) print(string.format("Memory Usage Pattern Test (5 cycles, 100 elements each): %.6f seconds", time)) -- Memory pattern test should complete within reasonable time luaunit.assertTrue(time < 3.0, "Memory usage pattern test should complete within 3 seconds") -- Verify container is clean after cycles luaunit.assertEquals(#container.children, 0, "Container should be clean after memory test") end -- Test 7: Performance with Different Layout Strategies function TestPerformance:testPerformanceWithDifferentLayoutStrategies() local strategies = { { name = "Simple Horizontal", props = { flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.FLEX_START, alignItems = AlignItems.STRETCH, }, }, { name = "Centered Vertical", props = { flexDirection = FlexDirection.VERTICAL, justifyContent = JustifyContent.CENTER, alignItems = AlignItems.CENTER, }, }, { name = "Wrapped Space-Between", props = { flexDirection = FlexDirection.HORIZONTAL, flexWrap = FlexWrap.WRAP, justifyContent = JustifyContent.SPACE_BETWEEN, alignItems = AlignItems.FLEX_START, }, }, } local times = {} for _, strategy in ipairs(strategies) do local container = createTestContainer(strategy.props) local children = createManyChildren(container, 40) local time, _ = measureTime(function() container:layoutChildren() end) times[strategy.name] = time print(string.format("Layout Strategy '%s': %.6f seconds", strategy.name, time)) -- Each strategy should complete within reasonable time luaunit.assertTrue(time < 1.0, string.format("'%s' layout should complete within 1 second", strategy.name)) end -- All strategies should perform reasonably similarly -- None should be more than 10x slower than the fastest local min_time = math.huge local max_time = 0 for _, time in pairs(times) do min_time = math.min(min_time, time) max_time = math.max(max_time, time) end luaunit.assertTrue(max_time <= min_time * 10, "Layout strategies should have similar performance characteristics") end -- Test 8: Stress Test with Maximum Elements function TestPerformance:testStressTestWithMaximumElements() local container = createTestContainer({ w = 1200, h = 900, flexDirection = FlexDirection.HORIZONTAL, flexWrap = FlexWrap.WRAP, }) -- Create a large number of children for stress testing local stress_count = 300 local children = createManyChildren(container, stress_count, { w = 30, h = 20, }) local time, _ = measureTime(function() container:layoutChildren() end) print(string.format("Stress Test (%d elements): %.6f seconds", stress_count, time)) -- Stress test should complete within reasonable time even with many elements luaunit.assertTrue( time < 5.0, string.format("Stress test with %d elements should complete within 5 seconds", stress_count) ) -- Verify that all children are positioned local positioned_count = 0 for _, child in ipairs(children) do if child.x >= 0 and child.y >= 0 then positioned_count = positioned_count + 1 end end luaunit.assertEquals(positioned_count, stress_count, "All children should be positioned in stress test") end -- Test 9: Complex Real-World Application Performance - Enterprise Dashboard function TestPerformance:testComplexEnterpriseApplicationPerformance() print("\n=== Test 9: Complex Enterprise Dashboard Performance ===") -- Create enterprise-grade dashboard with deep nesting (5 levels) local dashboard = createTestContainer({ w = 1920, h = 1080, flexDirection = FlexDirection.VERTICAL, gap = 10, }) local time, structure_info = measureTime(function() -- Level 1: Header, Main Content, Footer local header = Gui.new({ w = 1900, h = 80, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_BETWEEN, alignItems = AlignItems.CENTER, gap = 20, }) header.parent = dashboard table.insert(dashboard.children, header) local main_content = Gui.new({ w = 1900, h = 980, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, gap = 15, }) main_content.parent = dashboard table.insert(dashboard.children, main_content) local footer = Gui.new({ w = 1900, h = 60, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.CENTER, }) footer.parent = dashboard table.insert(dashboard.children, footer) -- Level 2: Header components (logo, navigation, user actions) local header_sections = { "logo", "navigation", "search", "notifications", "user_menu" } for i, section_name in ipairs(header_sections) do local section = Gui.new({ w = section_name == "navigation" and 400 or 150, h = 60, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.CENTER, alignItems = AlignItems.CENTER, }) section.parent = header table.insert(header.children, section) -- Level 3: Section items local item_count = section_name == "navigation" and 6 or 3 for j = 1, item_count do local item = Gui.new({ w = section_name == "navigation" and 60 or 45, h = 40, }) item.parent = section table.insert(section.children, item) end end -- Level 2: Main content areas (sidebar, dashboard grid) local sidebar = Gui.new({ w = 280, h = 960, positioning = Positioning.FLEX, flexDirection = FlexDirection.VERTICAL, gap = 10, }) sidebar.parent = main_content table.insert(main_content.children, sidebar) local dashboard_grid = Gui.new({ w = 1600, h = 960, positioning = Positioning.FLEX, flexDirection = FlexDirection.VERTICAL, gap = 20, }) dashboard_grid.parent = main_content table.insert(main_content.children, dashboard_grid) -- Level 3: Sidebar navigation items (complex menu structure) local menu_categories = { { name = "Analytics", items = 5 }, { name = "Reports", items = 7 }, { name = "Users", items = 4 }, { name = "Settings", items = 6 }, { name = "Tools", items = 8 }, } for _, category in ipairs(menu_categories) do local category_container = Gui.new({ w = 260, h = 40 + (category.items * 35), positioning = Positioning.FLEX, flexDirection = FlexDirection.VERTICAL, gap = 2, }) category_container.parent = sidebar table.insert(sidebar.children, category_container) -- Category header local category_header = Gui.new({ w = 250, h = 35 }) category_header.parent = category_container table.insert(category_container.children, category_header) -- Level 4: Menu items with sub-indicators for i = 1, category.items do local menu_item = Gui.new({ w = 240, h = 30, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_BETWEEN, alignItems = AlignItems.CENTER, }) menu_item.parent = category_container table.insert(category_container.children, menu_item) -- Level 5: Menu item components (text, icon, badge) local item_icon = Gui.new({ w = 20, h = 20 }) item_icon.parent = menu_item table.insert(menu_item.children, item_icon) local item_text = Gui.new({ w = 180, h = 25 }) item_text.parent = menu_item table.insert(menu_item.children, item_text) local item_badge = Gui.new({ w = 25, h = 18 }) item_badge.parent = menu_item table.insert(menu_item.children, item_badge) end end -- Level 3: Dashboard grid (4x3 widget grid with complex internals) for row = 1, 4 do local grid_row = Gui.new({ w = 1580, h = 220, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_BETWEEN, gap = 20, }) grid_row.parent = dashboard_grid table.insert(dashboard_grid.children, grid_row) for col = 1, 3 do local widget = Gui.new({ w = 500, h = 200, positioning = Positioning.FLEX, flexDirection = FlexDirection.VERTICAL, gap = 8, }) widget.parent = grid_row table.insert(grid_row.children, widget) -- Level 4: Widget components (header, content, footer) local widget_header = Gui.new({ w = 480, h = 40, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_BETWEEN, alignItems = AlignItems.CENTER, }) widget_header.parent = widget table.insert(widget.children, widget_header) local widget_content = Gui.new({ w = 480, h = 120, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, flexWrap = FlexWrap.WRAP, justifyContent = JustifyContent.SPACE_AROUND, alignItems = AlignItems.CENTER, gap = 5, }) widget_content.parent = widget table.insert(widget.children, widget_content) local widget_footer = Gui.new({ w = 480, h = 32, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.FLEX_END, alignItems = AlignItems.CENTER, }) widget_footer.parent = widget table.insert(widget.children, widget_footer) -- Level 5: Widget content elements (charts, metrics, etc.) local content_elements = (row * col) % 4 == 0 and 12 or 8 for i = 1, content_elements do local element = Gui.new({ w = content_elements > 10 and 35 or 55, h = content_elements > 10 and 25 or 35, }) element.parent = widget_content table.insert(widget_content.children, element) end -- Widget header components local widget_title = Gui.new({ w = 200, h = 30 }) widget_title.parent = widget_header table.insert(widget_header.children, widget_title) local widget_actions = Gui.new({ w = 120, h = 30, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, gap = 5, }) widget_actions.parent = widget_header table.insert(widget_header.children, widget_actions) for j = 1, 3 do local action_btn = Gui.new({ w = 30, h = 25 }) action_btn.parent = widget_actions table.insert(widget_actions.children, action_btn) end -- Widget footer components local footer_info = Gui.new({ w = 100, h = 25 }) footer_info.parent = widget_footer table.insert(widget_footer.children, footer_info) end end -- Perform complete layout dashboard:layoutChildren() -- Calculate structure metrics local total_elements = 0 local max_depth = 0 local function countElements(element, depth) total_elements = total_elements + 1 max_depth = math.max(max_depth, depth) for _, child in ipairs(element.children) do countElements(child, depth + 1) end end countElements(dashboard, 1) return { total_elements = total_elements, max_depth = max_depth, widgets = 12, menu_items = 30, } end) print(string.format("Enterprise Dashboard Performance:")) print(string.format(" Total Elements: %d", structure_info.total_elements)) print(string.format(" Maximum Depth: %d levels", structure_info.max_depth)) print(string.format(" Layout Time: %.6f seconds", time)) print(string.format(" Elements/Second: %.0f", structure_info.total_elements / time)) -- Performance assertions for enterprise-grade application luaunit.assertTrue(time < 8.0, "Enterprise dashboard should layout within 8 seconds") luaunit.assertTrue(structure_info.total_elements > 200, "Should have created substantial element count") luaunit.assertTrue(structure_info.max_depth >= 5, "Should have deep nesting structure") -- Verify critical components are positioned luaunit.assertEquals(#dashboard.children, 3, "Should have header, main, footer") luaunit.assertTrue(#dashboard.children[2].children >= 2, "Main should have sidebar and grid") end -- Test 10: High-Frequency Dynamic Layout Updates Performance function TestPerformance:testHighFrequencyDynamicLayoutUpdates() print("\n=== Test 10: High-Frequency Dynamic Updates Performance ===") local container = createTestContainer({ w = 1200, h = 800, flexDirection = FlexDirection.VERTICAL, gap = 10, }) -- Create dynamic content structure local sections = {} for i = 1, 8 do local section = Gui.new({ w = 1180, h = 90, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_BETWEEN, alignItems = AlignItems.CENTER, gap = 8, }) section.parent = container table.insert(container.children, section) table.insert(sections, section) -- Create dynamic items in each section for j = 1, 10 do local item = Gui.new({ w = 100, h = 70, positioning = Positioning.FLEX, flexDirection = FlexDirection.VERTICAL, justifyContent = JustifyContent.CENTER, alignItems = AlignItems.CENTER, }) item.parent = section table.insert(section.children, item) -- Sub-items for more complex updates for k = 1, 3 do local sub_item = Gui.new({ w = 80, h = 20 }) sub_item.parent = item table.insert(item.children, sub_item) end end end -- Initial layout container:layoutChildren() local update_scenarios = { { name = "Direction Changes", iterations = 50 }, { name = "Justify Content Cycling", iterations = 40 }, { name = "Gap Modifications", iterations = 30 }, { name = "Size Adjustments", iterations = 35 }, { name = "Wrap Toggle", iterations = 25 }, } local total_updates = 0 local total_time = 0 for _, scenario in ipairs(update_scenarios) do local scenario_time = measureTime(function() for i = 1, scenario.iterations do if scenario.name == "Direction Changes" then local section = sections[(i % #sections) + 1] section.flexDirection = (i % 2 == 0) and FlexDirection.VERTICAL or FlexDirection.HORIZONTAL section:layoutChildren() elseif scenario.name == "Justify Content Cycling" then local section = sections[(i % #sections) + 1] local justifies = { JustifyContent.FLEX_START, JustifyContent.CENTER, JustifyContent.FLEX_END, JustifyContent.SPACE_BETWEEN } section.justifyContent = justifies[(i % #justifies) + 1] section:layoutChildren() elseif scenario.name == "Gap Modifications" then local section = sections[(i % #sections) + 1] section.gap = (i % 20) + 5 section:layoutChildren() elseif scenario.name == "Size Adjustments" then local section = sections[(i % #sections) + 1] for _, child in ipairs(section.children) do child.w = 80 + (i % 40) child.h = 60 + (i % 20) end section:layoutChildren() elseif scenario.name == "Wrap Toggle" then local section = sections[(i % #sections) + 1] section.flexWrap = (i % 2 == 0) and FlexWrap.WRAP or FlexWrap.NOWRAP section:layoutChildren() end end end) total_updates = total_updates + scenario.iterations total_time = total_time + scenario_time print( string.format( " %s (%d updates): %.6f seconds (%.3f ms/update)", scenario.name, scenario.iterations, scenario_time, (scenario_time * 1000) / scenario.iterations ) ) end print(string.format("High-Frequency Updates Summary:")) print(string.format(" Total Updates: %d", total_updates)) print(string.format(" Total Time: %.6f seconds", total_time)) print(string.format(" Average Update Time: %.3f ms", (total_time * 1000) / total_updates)) print(string.format(" Updates Per Second: %.0f", total_updates / total_time)) -- Performance assertions luaunit.assertTrue(total_time < 15.0, "High-frequency updates should complete within 15 seconds") luaunit.assertTrue((total_time * 1000) / total_updates < 50, "Average update should be under 50ms") luaunit.assertTrue(total_updates / total_time > 10, "Should achieve at least 10 updates per second") -- Verify final state is valid luaunit.assertEquals(#container.children, 8, "All sections should still exist") for _, section in ipairs(sections) do luaunit.assertEquals(#section.children, 10, "All items should still exist in sections") end end -- Test 11: Complex Animation-Ready Layout Performance function TestPerformance:testComplexAnimationReadyLayoutPerformance() print("\n=== Test 11: Complex Animation-Ready Layout Performance ===") -- Create animation-heavy interface structure local animation_container = createTestContainer({ w = 1400, h = 900, flexDirection = FlexDirection.VERTICAL, gap = 15, }) local animation_elements = {} local time, metrics = measureTime(function() -- Create multiple animated sections with complex layouts for section_id = 1, 6 do local section = Gui.new({ w = 1380, h = 140, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_AROUND, alignItems = AlignItems.CENTER, gap = 12, }) section.parent = animation_container table.insert(animation_container.children, section) -- Create animated cards/panels for card_id = 1, 8 do local card = Gui.new({ w = 160, h = 120, positioning = Positioning.FLEX, flexDirection = FlexDirection.VERTICAL, justifyContent = JustifyContent.SPACE_BETWEEN, gap = 5, }) card.parent = section table.insert(section.children, card) table.insert(animation_elements, card) -- Card header with animated elements local card_header = Gui.new({ w = 150, h = 30, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_BETWEEN, alignItems = AlignItems.CENTER, }) card_header.parent = card table.insert(card.children, card_header) -- Animated header components local title = Gui.new({ w = 100, h = 25 }) title.parent = card_header table.insert(card_header.children, title) local status_indicator = Gui.new({ w = 20, h = 20 }) status_indicator.parent = card_header table.insert(card_header.children, status_indicator) -- Card content with animated metrics local card_content = Gui.new({ w = 150, h = 60, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, flexWrap = FlexWrap.WRAP, justifyContent = JustifyContent.SPACE_AROUND, alignItems = AlignItems.CENTER, gap = 3, }) card_content.parent = card table.insert(card.children, card_content) -- Animated metrics/values local metric_count = 4 + (section_id % 3) for i = 1, metric_count do local metric = Gui.new({ w = 35, h = 25, positioning = Positioning.FLEX, justifyContent = JustifyContent.CENTER, alignItems = AlignItems.CENTER, }) metric.parent = card_content table.insert(card_content.children, metric) table.insert(animation_elements, metric) end -- Card footer with action buttons local card_footer = Gui.new({ w = 150, h = 25, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.FLEX_END, gap = 5, }) card_footer.parent = card table.insert(card.children, card_footer) for i = 1, 2 do local action_btn = Gui.new({ w = 25, h = 20 }) action_btn.parent = card_footer table.insert(card_footer.children, action_btn) table.insert(animation_elements, action_btn) end end end -- Perform initial layout animation_container:layoutChildren() -- Simulate animation frame updates (position/size changes) local animation_frames = 60 -- Simulate 1 second at 60fps local frame_times = {} for frame = 1, animation_frames do local frame_start = os.clock() -- Simulate animated property changes for i, element in ipairs(animation_elements) do if (frame + i) % 10 == 0 then -- Animate size changes element.w = element.width + math.sin(frame * 0.1 + i) * 2 element.h = element.height + math.cos(frame * 0.1 + i) * 1 end if (frame + i) % 15 == 0 then -- Animate gap changes in parent containers if element.parent and element.parent.gap then element.parent.gap = 5 + math.abs(math.sin(frame * 0.05)) * 10 end end end -- Relayout for animation frame animation_container:layoutChildren() local frame_time = os.clock() - frame_start table.insert(frame_times, frame_time) end return { total_elements = #animation_elements, animation_frames = animation_frames, frame_times = frame_times, } end) -- Calculate animation performance metrics local total_frame_time = 0 local max_frame_time = 0 local min_frame_time = math.huge for _, frame_time in ipairs(metrics.frame_times) do total_frame_time = total_frame_time + frame_time max_frame_time = math.max(max_frame_time, frame_time) min_frame_time = math.min(min_frame_time, frame_time) end local avg_frame_time = total_frame_time / metrics.animation_frames local target_fps = 60 local target_frame_time = 1.0 / target_fps print(string.format("Animation-Ready Layout Performance:")) print(string.format(" Setup Time: %.6f seconds", time - total_frame_time)) print(string.format(" Animation Elements: %d", metrics.total_elements)) print(string.format(" Animation Frames: %d", metrics.animation_frames)) print(string.format(" Total Animation Time: %.6f seconds", total_frame_time)) print(string.format(" Average Frame Time: %.6f seconds (%.1f fps equivalent)", avg_frame_time, 1.0 / avg_frame_time)) print(string.format(" Min Frame Time: %.6f seconds", min_frame_time)) print(string.format(" Max Frame Time: %.6f seconds", max_frame_time)) print(string.format(" 60fps Target: %.6f seconds/frame", target_frame_time)) -- Performance assertions for animation-ready layouts luaunit.assertTrue(time < 12.0, "Animation setup should complete within 12 seconds") luaunit.assertTrue(avg_frame_time < target_frame_time * 2, "Average frame time should be reasonable for 30fps+") luaunit.assertTrue(max_frame_time < 0.1, "No single frame should take more than 100ms") luaunit.assertTrue(metrics.total_elements > 100, "Should have substantial number of animated elements") -- Verify structure integrity after animations luaunit.assertEquals(#animation_container.children, 6, "All sections should remain") local total_cards = 0 for _, section in ipairs(animation_container.children) do total_cards = total_cards + #section.children end luaunit.assertEquals(total_cards, 48, "All cards should remain after animation") end -- Test 12: Memory-Intensive Layout Performance with Cleanup function TestPerformance:testMemoryIntensiveLayoutPerformanceWithCleanup() print("\n=== Test 12: Memory-Intensive Layout with Cleanup ===") local memory_cycles = 8 local elements_per_cycle = 150 local cycle_times = {} local cleanup_times = {} local total_time = measureTime(function() for cycle = 1, memory_cycles do print(string.format(" Memory Cycle %d/%d", cycle, memory_cycles)) -- Create intensive layout structure local cycle_start = os.clock() local root = createTestContainer({ w = 1600, h = 1000, flexDirection = FlexDirection.VERTICAL, gap = 8, }) local all_elements = {} -- Create memory-intensive nested structure for level1 = 1, 10 do local section = Gui.new({ w = 1580, h = 95, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, flexWrap = FlexWrap.WRAP, justifyContent = JustifyContent.SPACE_AROUND, gap = 5, }) section.parent = root table.insert(root.children, section) table.insert(all_elements, section) for level2 = 1, 15 do local container = Gui.new({ w = 100, h = 85, positioning = Positioning.FLEX, flexDirection = FlexDirection.VERTICAL, justifyContent = JustifyContent.SPACE_BETWEEN, gap = 2, }) container.parent = section table.insert(section.children, container) table.insert(all_elements, container) for level3 = 1, 3 do local item = Gui.new({ w = 95, h = 25, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.CENTER, alignItems = AlignItems.CENTER, }) item.parent = container table.insert(container.children, item) table.insert(all_elements, item) -- Add some leaf nodes for memory pressure for level4 = 1, 2 do local leaf = Gui.new({ w = 40, h = 20 }) leaf.parent = item table.insert(item.children, leaf) table.insert(all_elements, leaf) end end end end -- Perform layout root:layoutChildren() local cycle_time = os.clock() - cycle_start table.insert(cycle_times, cycle_time) print(string.format(" Created %d elements in %.6f seconds", #all_elements, cycle_time)) -- Cleanup phase local cleanup_start = os.clock() -- Clear all references systematically for _, element in ipairs(all_elements) do element.children = {} element.parent = nil end -- Clear root structure root.children = {} Gui.destroy() -- Force garbage collection collectgarbage("collect") local cleanup_time = os.clock() - cleanup_start table.insert(cleanup_times, cleanup_time) print(string.format(" Cleanup completed in %.6f seconds", cleanup_time)) end end) -- Calculate memory performance metrics local total_cycle_time = 0 local total_cleanup_time = 0 local max_cycle_time = 0 local max_cleanup_time = 0 for i = 1, memory_cycles do total_cycle_time = total_cycle_time + cycle_times[i] total_cleanup_time = total_cleanup_time + cleanup_times[i] max_cycle_time = math.max(max_cycle_time, cycle_times[i]) max_cleanup_time = math.max(max_cleanup_time, cleanup_times[i]) end local avg_cycle_time = total_cycle_time / memory_cycles local avg_cleanup_time = total_cleanup_time / memory_cycles print(string.format("Memory-Intensive Layout Performance:")) print(string.format(" Memory Cycles: %d", memory_cycles)) print(string.format(" Elements Per Cycle: ~%d", elements_per_cycle * 6)) -- Approximate print(string.format(" Total Test Time: %.6f seconds", total_time)) print(string.format(" Average Cycle Time: %.6f seconds", avg_cycle_time)) print(string.format(" Average Cleanup Time: %.6f seconds", avg_cleanup_time)) print(string.format(" Max Cycle Time: %.6f seconds", max_cycle_time)) print(string.format(" Max Cleanup Time: %.6f seconds", max_cleanup_time)) print(string.format(" Cycle Efficiency: %.1f elements/second", (elements_per_cycle * 6) / avg_cycle_time)) -- Performance assertions for memory-intensive operations luaunit.assertTrue(total_time < 30.0, "Memory-intensive test should complete within 30 seconds") luaunit.assertTrue(avg_cycle_time < 5.0, "Average cycle should complete within 5 seconds") luaunit.assertTrue(avg_cleanup_time < 2.0, "Average cleanup should complete within 2 seconds") luaunit.assertTrue(max_cycle_time <= avg_cycle_time * 3, "No cycle should be extremely slow") luaunit.assertTrue(max_cleanup_time <= avg_cleanup_time * 3, "No cleanup should be extremely slow") -- Verify clean state after all cycles local final_container = createTestContainer() luaunit.assertEquals(#final_container.children, 0, "Should start with clean container after cycles") end -- Test 13: Extreme Scale Performance Benchmark function TestPerformance:testExtremeScalePerformanceBenchmark() print("\n=== Test 13: Extreme Scale Performance Benchmark ===") -- Test with extremely large layouts to find breaking points local scale_tests = { { name = "Massive Flat Layout", elements = 1000, depth = 1 }, { name = "Deep Nesting", elements = 200, depth = 10 }, { name = "Wide Branching", elements = 500, depth = 4 }, { name = "Mixed Complex", elements = 800, depth = 6 }, } local benchmark_results = {} for _, test_config in ipairs(scale_tests) do print(string.format(" Running %s test...", test_config.name)) local test_time, test_metrics = measureTime(function() local root = createTestContainer({ w = 2000, h = 1500, flexDirection = FlexDirection.VERTICAL, flexWrap = FlexWrap.WRAP, gap = 5, }) local created_elements = 0 local max_actual_depth = 0 if test_config.name == "Massive Flat Layout" then -- Create very wide, flat structure local items_per_row = 50 local rows = math.ceil(test_config.elements / items_per_row) for row = 1, rows do local row_container = Gui.new({ w = 1980, h = 25, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, flexWrap = FlexWrap.WRAP, gap = 2, }) row_container.parent = root table.insert(root.children, row_container) created_elements = created_elements + 1 local items_in_this_row = math.min(items_per_row, test_config.elements - (row - 1) * items_per_row) for col = 1, items_in_this_row do local item = Gui.new({ w = 35, h = 20 }) item.parent = row_container table.insert(row_container.children, item) created_elements = created_elements + 1 end end max_actual_depth = 2 elseif test_config.name == "Deep Nesting" then -- Create deep nested structure local current_parent = root local elements_per_level = math.ceil(test_config.elements / test_config.depth) for depth = 1, test_config.depth do local level_container = Gui.new({ w = 1900 - (depth * 50), h = 1400 - (depth * 100), positioning = Positioning.FLEX, flexDirection = (depth % 2 == 0) and FlexDirection.VERTICAL or FlexDirection.HORIZONTAL, flexWrap = FlexWrap.WRAP, gap = math.max(1, 10 - depth), }) level_container.parent = current_parent table.insert(current_parent.children, level_container) created_elements = created_elements + 1 if depth < test_config.depth then current_parent = level_container else -- Final level - add many elements for i = 1, elements_per_level do local leaf = Gui.new({ w = 30 + (i % 20), h = 25 + (i % 15) }) leaf.parent = level_container table.insert(level_container.children, leaf) created_elements = created_elements + 1 end end end max_actual_depth = test_config.depth elseif test_config.name == "Wide Branching" then -- Create structure with wide branching at each level local function createBranching(parent, remaining_elements, current_depth, max_depth) if current_depth >= max_depth or remaining_elements <= 0 then return 0 end local children_count = math.min(20, math.ceil(remaining_elements / (max_depth - current_depth))) local elements_used = 0 for i = 1, children_count do local branch = Gui.new({ w = 150 - (current_depth * 15), h = 100 - (current_depth * 10), positioning = Positioning.FLEX, flexDirection = (i % 2 == 0) and FlexDirection.VERTICAL or FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_AROUND, gap = math.max(1, 8 - current_depth * 2), }) branch.parent = parent table.insert(parent.children, branch) elements_used = elements_used + 1 if current_depth < max_depth - 1 then elements_used = elements_used + createBranching(branch, remaining_elements - elements_used, current_depth + 1, max_depth) end if elements_used >= remaining_elements then break end end return elements_used end created_elements = 1 + createBranching(root, test_config.elements - 1, 1, test_config.depth) max_actual_depth = test_config.depth elseif test_config.name == "Mixed Complex" then -- Create mixed complex structure with varying patterns local sections = math.ceil(test_config.depth / 2) local elements_per_section = math.ceil(test_config.elements / sections) for section_id = 1, sections do local section = Gui.new({ w = 1900, h = 200, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, flexWrap = FlexWrap.WRAP, justifyContent = JustifyContent.SPACE_BETWEEN, gap = 10, }) section.parent = root table.insert(root.children, section) created_elements = created_elements + 1 -- Create subsections with different patterns local subsections = 5 + (section_id % 3) for sub_id = 1, subsections do local subsection = Gui.new({ w = 300, h = 180, positioning = Positioning.FLEX, flexDirection = FlexDirection.VERTICAL, justifyContent = JustifyContent.SPACE_AROUND, gap = 5, }) subsection.parent = section table.insert(section.children, subsection) created_elements = created_elements + 1 -- Add elements with varying complexity local elements_in_subsection = math.ceil(elements_per_section / subsections) for elem_id = 1, elements_in_subsection do if elem_id % 3 == 0 then -- Complex element with children local complex_elem = Gui.new({ w = 280, h = 35, positioning = Positioning.FLEX, flexDirection = FlexDirection.HORIZONTAL, justifyContent = JustifyContent.SPACE_BETWEEN, gap = 3, }) complex_elem.parent = subsection table.insert(subsection.children, complex_elem) created_elements = created_elements + 1 for child_id = 1, 4 do local child = Gui.new({ w = 60, h = 30 }) child.parent = complex_elem table.insert(complex_elem.children, child) created_elements = created_elements + 1 end else -- Simple element local simple_elem = Gui.new({ w = 270, h = 25 }) simple_elem.parent = subsection table.insert(subsection.children, simple_elem) created_elements = created_elements + 1 end if created_elements >= test_config.elements then break end end if created_elements >= test_config.elements then break end end if created_elements >= test_config.elements then break end end max_actual_depth = 4 end -- Perform layout root:layoutChildren() return { created_elements = created_elements, max_depth = max_actual_depth, } end) local elements_per_second = test_metrics.created_elements / test_time benchmark_results[test_config.name] = { time = test_time, elements = test_metrics.created_elements, elements_per_second = elements_per_second, depth = test_metrics.max_depth, } print( string.format( " %s: %d elements, %.6f seconds (%.0f elem/sec)", test_config.name, test_metrics.created_elements, test_time, elements_per_second ) ) -- Individual test assertions luaunit.assertTrue(test_time < 20.0, string.format("%s should complete within 20 seconds", test_config.name)) luaunit.assertTrue( test_metrics.created_elements > 100, string.format("%s should create substantial elements", test_config.name) ) end -- Overall benchmark analysis print(string.format("Extreme Scale Benchmark Summary:")) local total_elements = 0 local total_time = 0 local best_performance = 0 local worst_performance = math.huge for test_name, result in pairs(benchmark_results) do total_elements = total_elements + result.elements total_time = total_time + result.time best_performance = math.max(best_performance, result.elements_per_second) worst_performance = math.min(worst_performance, result.elements_per_second) print(string.format(" %s: %.0f elements/second", test_name, result.elements_per_second)) end local avg_performance = total_elements / total_time print(string.format(" Overall Average: %.0f elements/second", avg_performance)) print(string.format(" Best Performance: %.0f elements/second", best_performance)) print(string.format(" Worst Performance: %.0f elements/second", worst_performance)) print(string.format(" Performance Range: %.1fx", best_performance / worst_performance)) -- Extreme scale performance assertions luaunit.assertTrue(total_time < 60.0, "All extreme scale tests should complete within 60 seconds") luaunit.assertTrue(avg_performance > 50, "Should achieve at least 50 elements/second average") luaunit.assertTrue(best_performance > 100, "Best case should achieve at least 100 elements/second") luaunit.assertTrue(best_performance / worst_performance < 20, "Performance variance should be reasonable") luaunit.assertTrue(total_elements > 2000, "Should have processed substantial total elements") end luaunit.LuaUnit.run()