#!/usr/bin/env python3 """ Comprehensive test script for the theme system refactoring. Tests all components without requiring PyQt5. """ import sys import os import json from pathlib import Path # Add project root to path sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) def test_theme_config(): """Test theme configuration module.""" print("\n=== Testing Theme Configuration ===") try: from themes.theme_config import ThemeConfig # Test light theme light = ThemeConfig.get_theme('light') print(f"✓ Light theme loaded: {len(light)} color definitions") # Test dark theme dark = ThemeConfig.get_theme('dark') print(f"✓ Dark theme loaded: {len(dark)} color definitions") # Check critical keys critical_keys = [ 'bg_primary', 'bg_secondary', 'bg_tertiary', 'text_primary', 'text_secondary', 'text_tertiary', 'accent', 'accent_hover', 'accent_pressed', 'error', 'error_dark', 'success', 'warning', 'border_default', 'border_subtle', 'logo_path' ] for key in critical_keys: if key not in light: print(f"✗ Missing in light theme: {key}") return False if key not in dark: print(f"✗ Missing in dark theme: {key}") return False print(f"✓ All {len(critical_keys)} critical keys present in both themes") # Test sizes, fonts, etc sizes = ThemeConfig.FONT_SIZES fonts = ThemeConfig.FONTS weights = ThemeConfig.FONT_WEIGHTS spacing = ThemeConfig.SPACING radius = ThemeConfig.RADIUS print(f"✓ Font sizes defined: {list(sizes.keys())}") print(f"✓ Font families defined: {list(fonts.keys())}") print(f"✓ Font weights defined: {list(weights.keys())}") print(f"✓ Spacing values defined: {list(spacing.keys())}") print(f"✓ Border radius defined: {list(radius.keys())}") return True except Exception as e: print(f"✗ Error testing theme config: {e}") return False def test_qss_generator(): """Test QSS generation.""" print("\n=== Testing QSS Generator ===") try: from themes.qss_generator import QSSGenerator # Generate light theme QSS light_qss = QSSGenerator.generate('light') print(f"✓ Light theme QSS generated: {len(light_qss)} characters") # Generate dark theme QSS dark_qss = QSSGenerator.generate('dark') print(f"✓ Dark theme QSS generated: {len(dark_qss)} characters") # Check for key selectors key_selectors = [ 'QMainWindow', 'QPushButton', 'QLabel', 'QLineEdit', 'QTextEdit', 'QScrollArea', 'QFrame', 'QWidget', 'QMenuBar', 'QTabBar', 'QDialog' ] missing_light = [] missing_dark = [] for selector in key_selectors: if selector not in light_qss: missing_light.append(selector) if selector not in dark_qss: missing_dark.append(selector) if missing_light: print(f"✗ Missing selectors in light QSS: {missing_light}") if missing_dark: print(f"✗ Missing selectors in dark QSS: {missing_dark}") if not missing_light and not missing_dark: print(f"✓ All {len(key_selectors)} key selectors present in both themes") # Check for object name selectors (our custom ones) custom_selectors = [ '#platform_button', '#filter_button', '#account_username', '#account_login_btn', '#account_export_btn', '#account_delete_btn', '#logo_button', '#dark_mode_toggle' ] found_custom = [] for selector in custom_selectors: if selector in light_qss: found_custom.append(selector) print(f"✓ Custom selectors found: {len(found_custom)}/{len(custom_selectors)}") return True except Exception as e: print(f"✗ Error testing QSS generator: {e}") return False def test_file_structure(): """Test that all required files exist.""" print("\n=== Testing File Structure ===") required_files = [ 'themes/__init__.py', 'themes/theme_config.py', 'themes/qss_generator.py', 'views/base/__init__.py', 'views/base/theme_aware_widget.py', 'views/widgets/dark_mode_toggle.py', 'utils/theme_manager.py', 'resources/icons/intelsight-logo.svg', 'resources/icons/intelsight-dark.svg' ] missing = [] for file in required_files: path = Path(file) if path.exists(): print(f"✓ {file}") else: print(f"✗ Missing: {file}") missing.append(file) if missing: print(f"\n✗ Missing {len(missing)} required files") return False else: print(f"\n✓ All {len(required_files)} required files present") return True def test_no_hardcoded_colors(): """Check for hardcoded colors in view files.""" print("\n=== Checking for Hardcoded Colors ===") import re # Pattern to match hex colors hex_pattern = re.compile(r'#[0-9A-Fa-f]{6}|#[0-9A-Fa-f]{3}') rgb_pattern = re.compile(r'rgb\s*\([^)]+\)|rgba\s*\([^)]+\)') view_files = [ 'views/main_window.py', 'views/platform_selector.py', 'views/components/tab_navigation.py', 'views/components/platform_grid_view.py', 'views/components/accounts_overview_view.py', 'views/widgets/platform_button.py', 'views/widgets/account_card.py' ] files_with_colors = [] for file in view_files: if not Path(file).exists(): continue with open(file, 'r') as f: content = f.read() # Skip import statements and comments lines = content.split('\n') for i, line in enumerate(lines): # Skip comments and imports if line.strip().startswith('#') or line.strip().startswith('from') or line.strip().startswith('import'): continue # Check for hex colors if 'setStyleSheet' in line and (hex_pattern.search(line) or rgb_pattern.search(line)): files_with_colors.append((file, i+1, line.strip())) if files_with_colors: print(f"✗ Found {len(files_with_colors)} lines with hardcoded colors:") for file, line_no, line in files_with_colors[:5]: # Show first 5 print(f" {file}:{line_no}: {line[:60]}...") return False else: print(f"✓ No hardcoded colors found in {len(view_files)} view files") return True def test_imports(): """Test that all imports work correctly.""" print("\n=== Testing Imports ===") test_imports = [ ('themes.theme_config', 'ThemeConfig'), ('themes.qss_generator', 'QSSGenerator'), ('views.base.theme_aware_widget', 'ThemeAwareWidget'), ] failed = [] for module_name, class_name in test_imports: try: module = __import__(module_name, fromlist=[class_name]) if hasattr(module, class_name): print(f"✓ {module_name}.{class_name}") else: print(f"✗ {module_name} missing {class_name}") failed.append(f"{module_name}.{class_name}") except ImportError as e: # Check if it's just PyQt5 missing if 'PyQt5' in str(e): print(f"⚠ {module_name}.{class_name} (requires PyQt5)") else: print(f"✗ {module_name}.{class_name}: {e}") failed.append(f"{module_name}.{class_name}") if failed: print(f"\n✗ {len(failed)} imports failed") return False else: print(f"\n✓ All critical imports successful (PyQt5-dependent modules skipped)") return True def main(): """Run all tests.""" print("=" * 60) print("THEME SYSTEM COMPREHENSIVE TEST") print("=" * 60) results = [] # Run tests results.append(("File Structure", test_file_structure())) results.append(("Theme Config", test_theme_config())) results.append(("QSS Generator", test_qss_generator())) results.append(("Imports", test_imports())) results.append(("No Hardcoded Colors", test_no_hardcoded_colors())) # Summary print("\n" + "=" * 60) print("TEST SUMMARY") print("=" * 60) passed = sum(1 for _, result in results if result) total = len(results) for name, result in results: status = "✓ PASS" if result else "✗ FAIL" print(f"{status}: {name}") print(f"\nTotal: {passed}/{total} tests passed") if passed == total: print("\n✅ ALL TESTS PASSED! Theme system is properly configured.") else: print(f"\n⚠️ {total - passed} tests failed. Review the output above.") return 0 if passed == total else 1 if __name__ == "__main__": sys.exit(main())