537 lines
20 KiB
Python
537 lines
20 KiB
Python
"""
|
|
Performance Tests
|
|
|
|
Tests for UI performance including:
|
|
- Startup time
|
|
- Animation smoothness
|
|
- Memory usage
|
|
- Rendering performance
|
|
- Plugin loading speed
|
|
"""
|
|
|
|
|
|
class PerformanceTests:
|
|
"""Test suite for performance."""
|
|
|
|
name = "Performance"
|
|
icon = "⚡"
|
|
description = "Tests startup time, animation smoothness, memory usage, and rendering performance"
|
|
|
|
def __init__(self):
|
|
self.tests = {
|
|
'animation_performance': self.test_animation_performance,
|
|
'stylesheet_efficiency': self.test_stylesheet_efficiency,
|
|
'plugin_loading': self.test_plugin_loading,
|
|
'widget_creation_speed': self.test_widget_creation_speed,
|
|
'rendering_performance': self.test_rendering_performance,
|
|
'memory_efficiency': self.test_memory_efficiency,
|
|
'responsive_breakpoints': self.test_responsive_breakpoints,
|
|
'lazy_loading': self.test_lazy_loading,
|
|
'caching': self.test_caching,
|
|
'optimization_flags': self.test_optimization_flags,
|
|
}
|
|
|
|
def test_animation_performance(self) -> dict:
|
|
"""Test animation performance settings."""
|
|
try:
|
|
from core.eu_styles import AnimationHelper
|
|
from core.overlay_window import OverlayWindow
|
|
|
|
issues = []
|
|
recommendations = []
|
|
|
|
# Check animation durations
|
|
if hasattr(OverlayWindow, '_setup_animations'):
|
|
import inspect
|
|
source = inspect.getsource(OverlayWindow._setup_animations)
|
|
|
|
# Check for reasonable durations
|
|
import re
|
|
durations = re.findall(r'setDuration\((\d+)\)', source)
|
|
durations = [int(d) for d in durations]
|
|
|
|
if durations:
|
|
avg_duration = sum(durations) / len(durations)
|
|
if avg_duration > 500:
|
|
recommendations.append(f"Average animation duration ({avg_duration}ms) may be too long")
|
|
if max(durations) > 1000:
|
|
issues.append(f"Animation duration too long: {max(durations)}ms")
|
|
|
|
# Check easing curves
|
|
if hasattr(AnimationHelper, 'fade_in'):
|
|
import inspect
|
|
source = inspect.getsource(AnimationHelper.fade_in)
|
|
|
|
if 'easing' not in source.lower():
|
|
recommendations.append("Consider using easing curves for smoother animations")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'warning',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': f"Animation performance checked ({len(durations) if 'durations' in dir() else 'N/A'} animations)",
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking animation performance: {e}",
|
|
'severity': 'error'
|
|
}
|
|
|
|
def test_stylesheet_efficiency(self) -> dict:
|
|
"""Test stylesheet efficiency."""
|
|
try:
|
|
from core.eu_styles import get_global_stylesheet
|
|
|
|
issues = []
|
|
recommendations = []
|
|
|
|
style = get_global_stylesheet()
|
|
|
|
# Check size
|
|
if len(style) > 10000:
|
|
recommendations.append(f"Global stylesheet is large ({len(style)} chars), consider optimization")
|
|
|
|
# Check for redundant styles
|
|
lines = style.split('\n')
|
|
if len(lines) > 500:
|
|
recommendations.append(f"Stylesheet has many lines ({len(lines)}), consider consolidation")
|
|
|
|
# Check for efficient selectors
|
|
universal_selectors = style.count('*')
|
|
if universal_selectors > 5:
|
|
recommendations.append(f"Many universal selectors ({universal_selectors}) may impact performance")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'warning'
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': f"Stylesheet efficiency checked ({len(style)} chars, {len(lines)} lines)",
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking stylesheet efficiency: {e}",
|
|
'severity': 'error'
|
|
}
|
|
|
|
def test_plugin_loading(self) -> dict:
|
|
"""Test plugin loading performance."""
|
|
try:
|
|
from core.overlay_window import OverlayWindow
|
|
from core.plugin_manager import PluginManager
|
|
|
|
issues = []
|
|
recommendations = []
|
|
|
|
# Check plugin loading method
|
|
if not hasattr(OverlayWindow, '_load_plugins'):
|
|
issues.append("_load_plugins method missing")
|
|
|
|
# Check for lazy loading indicators
|
|
import inspect
|
|
if hasattr(OverlayWindow, '_load_plugins'):
|
|
source = inspect.getsource(OverlayWindow._load_plugins)
|
|
|
|
# Should handle errors gracefully
|
|
if 'try' not in source or 'except' not in source:
|
|
recommendations.append("Consider adding error handling to _load_plugins")
|
|
|
|
# Check for UI freezing prevention
|
|
if 'processEvents' not in source:
|
|
recommendations.append("Consider calling processEvents during plugin loading to prevent UI freeze")
|
|
|
|
# Check plugin manager efficiency
|
|
if hasattr(PluginManager, 'get_all_plugins'):
|
|
# Method exists, good
|
|
pass
|
|
else:
|
|
recommendations.append("PluginManager should have efficient get_all_plugins method")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'error',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': "Plugin loading performance features checked",
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking plugin loading: {e}",
|
|
'severity': 'error'
|
|
}
|
|
|
|
def test_widget_creation_speed(self) -> dict:
|
|
"""Test widget creation speed."""
|
|
try:
|
|
from core.widget_registry import get_widget_registry
|
|
from core.overlay_window import OverlayWindow
|
|
|
|
issues = []
|
|
recommendations = []
|
|
|
|
# Check widget registry efficiency
|
|
registry = get_widget_registry()
|
|
|
|
if not hasattr(registry, 'create_widget'):
|
|
issues.append("WidgetRegistry.create_widget missing")
|
|
|
|
# Check for widget pooling
|
|
recommendations.append("Consider implementing widget pooling for frequently created widgets")
|
|
|
|
# Check overlay widget creation
|
|
if hasattr(OverlayWindow, '_add_registered_widget'):
|
|
import inspect
|
|
source = inspect.getsource(OverlayWindow._add_registered_widget)
|
|
|
|
if 'show' not in source:
|
|
recommendations.append("Widgets should be shown immediately after creation")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'warning',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': "Widget creation speed features checked",
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking widget creation: {e}",
|
|
'severity': 'error'
|
|
}
|
|
|
|
def test_rendering_performance(self) -> dict:
|
|
"""Test rendering performance optimizations."""
|
|
try:
|
|
from core.overlay_window import OverlayWindow
|
|
from core.activity_bar import ActivityBar
|
|
|
|
issues = []
|
|
recommendations = []
|
|
|
|
# Check for render hints
|
|
import inspect
|
|
|
|
if hasattr(ActivityBar, '_setup_window'):
|
|
source = inspect.getsource(ActivityBar._setup_window)
|
|
|
|
# Check for translucent background
|
|
if 'translucent' not in source.lower():
|
|
recommendations.append("ActivityBar should use translucent background for performance")
|
|
|
|
# Check for double buffering
|
|
if hasattr(OverlayWindow, '_setup_window'):
|
|
source = inspect.getsource(OverlayWindow._setup_window)
|
|
|
|
# Check for render hints
|
|
if 'renderhint' not in source.lower():
|
|
recommendations.append("Consider setting render hints for smooth rendering")
|
|
|
|
# Check for update throttling
|
|
recommendations.append("Consider implementing update throttling for frequent updates")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'warning'
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': "Rendering performance features checked",
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking rendering performance: {e}",
|
|
'severity': 'error'
|
|
}
|
|
|
|
def test_memory_efficiency(self) -> dict:
|
|
"""Test memory efficiency."""
|
|
try:
|
|
from core.overlay_window import OverlayWindow
|
|
from core.widget_registry import get_widget_registry
|
|
|
|
issues = []
|
|
recommendations = []
|
|
|
|
# Check for widget cleanup
|
|
if not hasattr(OverlayWindow, '_active_widgets'):
|
|
recommendations.append("Consider tracking _active_widgets to manage memory")
|
|
|
|
# Check registry cleanup
|
|
registry = get_widget_registry()
|
|
|
|
if not hasattr(registry, 'clear'):
|
|
recommendations.append("WidgetRegistry should have clear method for cleanup")
|
|
|
|
if not hasattr(registry, 'unregister_widget'):
|
|
recommendations.append("WidgetRegistry should have unregister_widget for cleanup")
|
|
|
|
# Check for explicit deletion
|
|
import inspect
|
|
if hasattr(OverlayWindow, '_reload_plugins'):
|
|
source = inspect.getsource(OverlayWindow._reload_plugins)
|
|
|
|
if 'deleteLater' not in source and 'removeWidget' not in source:
|
|
recommendations.append("Consider explicit widget cleanup in _reload_plugins")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'warning',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': "Memory efficiency features checked",
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking memory efficiency: {e}",
|
|
'severity': 'error'
|
|
}
|
|
|
|
def test_responsive_breakpoints(self) -> dict:
|
|
"""Test responsive breakpoint handling."""
|
|
try:
|
|
from core.eu_styles import ResponsiveHelper
|
|
from core.overlay_window import OverlayWindow
|
|
|
|
issues = []
|
|
|
|
# Check breakpoints
|
|
if not hasattr(ResponsiveHelper, 'BREAKPOINTS'):
|
|
issues.append("ResponsiveHelper.BREAKPOINTS missing")
|
|
else:
|
|
breakpoints = ResponsiveHelper.BREAKPOINTS
|
|
|
|
expected = ['sm', 'md', 'lg', 'xl']
|
|
missing = [e for e in expected if e not in breakpoints]
|
|
|
|
if missing:
|
|
issues.append(f"Missing breakpoints: {missing}")
|
|
|
|
# Check responsive methods
|
|
if not hasattr(ResponsiveHelper, 'get_breakpoint'):
|
|
issues.append("ResponsiveHelper.get_breakpoint missing")
|
|
|
|
if not hasattr(ResponsiveHelper, 'should_show_sidebar'):
|
|
issues.append("ResponsiveHelper.should_show_sidebar missing")
|
|
|
|
# Check overlay integration
|
|
if not hasattr(OverlayWindow, 'resizeEvent'):
|
|
issues.append("resizeEvent not implemented for responsive behavior")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'warning'
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': f"Responsive breakpoints configured: {ResponsiveHelper.BREAKPOINTS if hasattr(ResponsiveHelper, 'BREAKPOINTS') else 'N/A'}",
|
|
'severity': 'info'
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking responsive breakpoints: {e}",
|
|
'severity': 'error'
|
|
}
|
|
|
|
def test_lazy_loading(self) -> dict:
|
|
"""Test lazy loading implementation."""
|
|
try:
|
|
from core.overlay_window import OverlayWindow
|
|
from core.plugin_store import PluginStoreUI
|
|
|
|
issues = []
|
|
recommendations = []
|
|
|
|
# Check for lazy loading indicators
|
|
import inspect
|
|
|
|
# Check plugin store
|
|
if hasattr(PluginStoreUI, 'refresh_plugins'):
|
|
source = inspect.getsource(PluginStoreUI.refresh_plugins)
|
|
|
|
# Should load on demand
|
|
if 'lazy' not in source.lower():
|
|
recommendations.append("Consider implementing lazy loading for plugin store")
|
|
|
|
# Check widget tab refresh
|
|
if hasattr(OverlayWindow, '_refresh_widgets_tab'):
|
|
recommendations.append("Consider caching widgets tab content to avoid repeated rebuilds")
|
|
|
|
# Check settings
|
|
if hasattr(OverlayWindow, '_create_plugins_settings_tab'):
|
|
recommendations.append("Consider lazy loading plugin settings content")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': "Lazy loading opportunities identified",
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking lazy loading: {e}",
|
|
'severity': 'error'
|
|
}
|
|
|
|
def test_caching(self) -> dict:
|
|
"""Test caching implementation."""
|
|
try:
|
|
from core.icon_manager import get_icon_manager
|
|
from core.eu_styles import get_global_stylesheet
|
|
|
|
issues = []
|
|
recommendations = []
|
|
|
|
# Check icon caching
|
|
try:
|
|
icon_mgr = get_icon_manager()
|
|
|
|
if not hasattr(icon_mgr, '_cache'):
|
|
recommendations.append("IconManager should cache loaded icons")
|
|
except Exception as e:
|
|
recommendations.append(f"IconManager caching not verified: {e}")
|
|
|
|
# Check stylesheet caching potential
|
|
recommendations.append("Consider caching generated stylesheets")
|
|
|
|
# Check color caching
|
|
recommendations.append("Consider caching color lookups")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': "Caching opportunities identified",
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking caching: {e}",
|
|
'severity': 'error'
|
|
}
|
|
|
|
def test_optimization_flags(self) -> dict:
|
|
"""Test optimization flags and settings."""
|
|
try:
|
|
from core.overlay_window import OverlayWindow
|
|
from core.activity_bar import ActivityBar
|
|
|
|
issues = []
|
|
recommendations = []
|
|
|
|
# Check for WA_DeleteOnClose
|
|
import inspect
|
|
|
|
if hasattr(ActivityBar, '_setup_window'):
|
|
source = inspect.getsource(ActivityBar._setup_window)
|
|
|
|
if 'DeleteOnClose' not in source:
|
|
recommendations.append("ActivityBar should set WA_DeleteOnClose")
|
|
|
|
# Check for WA_TranslucentBackground
|
|
if hasattr(ActivityBar, '_setup_window'):
|
|
source = inspect.getsource(ActivityBar._setup_window)
|
|
|
|
if 'TranslucentBackground' not in source:
|
|
issues.append("ActivityBar should set WA_TranslucentBackground for performance")
|
|
|
|
# Check for optimization imports
|
|
recommendations.append("Consider importing performance optimizations module")
|
|
|
|
if issues:
|
|
return {
|
|
'passed': False,
|
|
'message': "; ".join(issues),
|
|
'severity': 'warning',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
return {
|
|
'passed': True,
|
|
'message': "Optimization flags checked",
|
|
'severity': 'info',
|
|
'recommendation': recommendations[0] if recommendations else None
|
|
}
|
|
|
|
except Exception as e:
|
|
return {
|
|
'passed': False,
|
|
'message': f"Error checking optimization flags: {e}",
|
|
'severity': 'error'
|
|
}
|