#!/usr/bin/env python3 """ Test button persistence throughout a live session """ import sys import asyncio import time from pathlib import Path # Add analyzer to path sys.path.insert(0, str(Path(__file__).parent)) from analyzer.tui.textual.app_v2 import StreamLensAppV2 from analyzer.analysis.core import EthernetAnalyzer from analyzer.models.flow_stats import FlowStats, FrameTypeStats from textual_inspector import inspect_textual_app, print_widget_tree async def simulate_data_loading_with_monitoring(): """Simulate data loading while monitoring button persistence""" print("๐Ÿงช Testing Button Persistence Throughout Session") print("=" * 60) # Create analyzer and app analyzer = EthernetAnalyzer() app = StreamLensAppV2(analyzer=analyzer) async with app.run_test() as pilot: print("๐Ÿ“ฑ App started - checking initial button state...") # Helper function to count buttons def count_buttons(): app_data = inspect_textual_app(app) button_count = 0 visible_buttons = 0 properly_sized = 0 def count_buttons_recursive(widget_data): nonlocal button_count, visible_buttons, properly_sized if widget_data.get('type') == 'Button' or 'Button' in widget_data.get('type', ''): button_count += 1 if widget_data.get('visible', False): visible_buttons += 1 size = widget_data.get('size', {}) if size.get('width', 0) > 0 and size.get('height', 0) > 0: properly_sized += 1 for child in widget_data.get('children', []): count_buttons_recursive(child) count_buttons_recursive(app_data.get('current_screen', {})) return button_count, visible_buttons, properly_sized # Phase 1: Initial state (no data) await asyncio.sleep(1) total1, visible1, sized1 = count_buttons() print(f"๐Ÿ“Š Phase 1 (Initial): {total1} total, {visible1} visible, {sized1} properly sized") # Phase 2: Add some flows to trigger refresh print("\n๐Ÿ”„ Phase 2: Adding flow data to trigger refresh...") # Add flows with different frame types flow1 = FlowStats(src_ip="192.168.1.1", dst_ip="192.168.1.2") flow1.frame_types["CH10-Data"] = FrameTypeStats("CH10-Data", count=100) flow1.frame_types["UDP"] = FrameTypeStats("UDP", count=50) analyzer.flows["flow1"] = flow1 flow2 = FlowStats(src_ip="192.168.1.3", dst_ip="192.168.1.4") flow2.frame_types["PTP-Sync"] = FrameTypeStats("PTP-Sync", count=200) flow2.frame_types["PTP-Signaling"] = FrameTypeStats("PTP-Signaling", count=75) analyzer.flows["flow2"] = flow2 # Wait for UI to process the changes await asyncio.sleep(2) total2, visible2, sized2 = count_buttons() print(f"๐Ÿ“Š Phase 2 (With Data): {total2} total, {visible2} visible, {sized2} properly sized") # Phase 3: Add more data to test ordering/refresh print("\n๐Ÿ”„ Phase 3: Adding more data to test refresh logic...") flow3 = FlowStats(src_ip="192.168.1.5", dst_ip="192.168.1.6") flow3.frame_types["TMATS"] = FrameTypeStats("TMATS", count=500) # High count should reorder flow3.frame_types["TCP"] = FrameTypeStats("TCP", count=25) analyzer.flows["flow3"] = flow3 # Wait for refresh await asyncio.sleep(2) total3, visible3, sized3 = count_buttons() print(f"๐Ÿ“Š Phase 3 (More Data): {total3} total, {visible3} visible, {sized3} properly sized") # Phase 4: Final check with detailed analysis print("\n๐Ÿ” Phase 4: Detailed button analysis...") app_data = inspect_textual_app(app) buttons_found = [] def analyze_buttons(widget_data, path=""): if widget_data.get('type') == 'Button' or 'Button' in widget_data.get('type', ''): button_info = { 'id': widget_data.get('id'), 'label': widget_data.get('label', 'NO LABEL'), 'visible': widget_data.get('visible', False), 'size': widget_data.get('size', {}), 'classes': widget_data.get('classes', []) } buttons_found.append(button_info) for child in widget_data.get('children', []): analyze_buttons(child, f"{path}/{widget_data.get('type', 'Unknown')}") analyze_buttons(app_data.get('current_screen', {})) print(f"\n๐Ÿ“‹ Final Button States:") for i, button in enumerate(buttons_found, 1): label = button.get('label', 'NO LABEL') size = button.get('size', {}) visible = button.get('visible', False) status_icons = [] if visible: status_icons.append("๐Ÿ‘๏ธ") if size.get('height', 0) > 0: status_icons.append("๐Ÿ“") if label and label != 'NO LABEL': status_icons.append("๐Ÿ“") status = " ".join(status_icons) if status_icons else "โŒ" print(f" {i:2d}. {button.get('id', 'unknown'):20} '{label:12}' {size.get('width', 0):2d}x{size.get('height', 0)} {status}") # Summary print(f"\n๐Ÿ“ˆ PERSISTENCE TEST RESULTS:") print(f" Phase 1 (Initial): {total1:2d} buttons ({visible1} visible, {sized1} sized)") print(f" Phase 2 (Data): {total2:2d} buttons ({visible2} visible, {sized2} sized)") print(f" Phase 3 (More): {total3:2d} buttons ({visible3} visible, {sized3} sized)") # Check for consistency if total1 == total2 == total3: print(f" โœ… BUTTON COUNT STABLE throughout session") else: print(f" ๐Ÿšจ Button count changed: {total1} โ†’ {total2} โ†’ {total3}") if visible1 == visible2 == visible3: print(f" โœ… BUTTON VISIBILITY STABLE throughout session") else: print(f" ๐Ÿšจ Visibility changed: {visible1} โ†’ {visible2} โ†’ {visible3}") if sized1 == sized2 == sized3 and sized3 > 0: print(f" โœ… BUTTON SIZING STABLE and working throughout session") else: print(f" ๐Ÿšจ Sizing changed: {sized1} โ†’ {sized2} โ†’ {sized3}") # Final verdict all_stable = (total1 == total2 == total3 and visible1 == visible2 == visible3 and sized1 == sized2 == sized3 and sized3 > 0) if all_stable: print(f"\n๐ŸŽ‰ SUCCESS: Buttons persist properly throughout the session!") else: print(f"\nโš ๏ธ Issues detected in button persistence") return all_stable def main(): print("๐Ÿงช StreamLens Button Persistence Test") print("This test simulates a full session with data loading") print("=" * 60) try: success = asyncio.run(simulate_data_loading_with_monitoring()) if success: print(f"\nโœ… All button persistence tests PASSED!") print(f"\n๐ŸŽฏ Both issues have been resolved:") print(f" โœ… Buttons persist throughout the session") print(f" โœ… Button text is visible (proper height)") else: print(f"\nโŒ Some persistence issues remain") except KeyboardInterrupt: print("\n๐Ÿ›‘ Test interrupted by user") except Exception as e: print(f"\nโŒ Test failed with error: {e}") import traceback traceback.print_exc() if __name__ == "__main__": main()