""" Tests for the Theme Manager UI component (Story 7.11). """ import pytest from pathlib import Path import tempfile from PyQt6.QtWidgets import QApplication from src.ui.theme_manager import ( ThemeMode, ThemeColors, ThemeManager, LIGHT_COLORS, DARK_COLORS, get_theme_manager, ) @pytest.fixture def app(qtbot): """Create QApplication for tests.""" return QApplication.instance() or QApplication([]) @pytest.fixture def clean_manager(): """Create a fresh ThemeManager for testing.""" # Reset singleton import src.ui.theme_manager as tm tm._theme_manager_instance = None manager = ThemeManager() return manager class TestThemeMode: """Tests for ThemeMode enum.""" def test_theme_mode_values(self): """Test ThemeMode enum values.""" assert ThemeMode.LIGHT.value == "light" assert ThemeMode.DARK.value == "dark" assert ThemeMode.AUTO.value == "auto" class TestThemeColors: """Tests for ThemeColors dataclass.""" def test_light_colors_structure(self): """Test light colors have all required fields.""" assert hasattr(LIGHT_COLORS, "window_bg") assert hasattr(LIGHT_COLORS, "window_text") assert hasattr(LIGHT_COLORS, "highlight") assert hasattr(LIGHT_COLORS, "success") assert hasattr(LIGHT_COLORS, "warning") assert hasattr(LIGHT_COLORS, "error") def test_dark_colors_structure(self): """Test dark colors have all required fields.""" assert hasattr(DARK_COLORS, "window_bg") assert hasattr(DARK_COLORS, "window_text") assert hasattr(DARK_COLORS, "highlight") assert hasattr(DARK_COLORS, "success") assert hasattr(DARK_COLORS, "warning") assert hasattr(DARK_COLORS, "error") def test_light_and_dark_differ(self): """Test that light and dark themes are different.""" assert LIGHT_COLORS.window_bg != DARK_COLORS.window_bg assert LIGHT_COLORS.window_text != DARK_COLORS.window_text class TestThemeManager: """Tests for ThemeManager.""" def test_initialization(self, clean_manager): """Test manager initialization.""" assert clean_manager.current_mode == ThemeMode.LIGHT def test_set_theme_light(self, clean_manager): """Test setting light theme.""" clean_manager.set_theme(ThemeMode.LIGHT) assert clean_manager.current_mode == ThemeMode.LIGHT assert clean_manager.colors == LIGHT_COLORS def test_set_theme_dark(self, clean_manager): """Test setting dark theme.""" clean_manager.set_theme(ThemeMode.DARK) assert clean_manager.current_mode == ThemeMode.DARK assert clean_manager.colors == DARK_COLORS def test_toggle_theme(self, clean_manager): """Test toggling between themes.""" clean_manager.set_theme(ThemeMode.LIGHT) clean_manager.toggle_theme() assert clean_manager.current_mode == ThemeMode.DARK clean_manager.toggle_theme() assert clean_manager.current_mode == ThemeMode.LIGHT def test_generate_stylesheet(self, clean_manager): """Test stylesheet generation.""" stylesheet = clean_manager.generate_stylesheet() assert isinstance(stylesheet, str) assert len(stylesheet) > 0 assert "QWidget" in stylesheet assert "QPushButton" in stylesheet assert "QLineEdit" in stylesheet def test_stylesheet_contains_colors(self, clean_manager): """Test that stylesheet contains current theme colors.""" clean_manager.set_theme(ThemeMode.DARK) stylesheet = clean_manager.generate_stylesheet() assert DARK_COLORS.window_bg in stylesheet assert DARK_COLORS.highlight in stylesheet def test_apply_to_application(self, app, clean_manager): """Test applying theme to application.""" clean_manager.set_theme(ThemeMode.DARK) clean_manager.apply_to_application(app) # Stylesheet should be set assert app.styleSheet() != "" def test_get_color(self, clean_manager): """Test getting individual colors.""" clean_manager.set_theme(ThemeMode.LIGHT) highlight = clean_manager.get_color("highlight") assert highlight == LIGHT_COLORS.highlight window_bg = clean_manager.get_color("window_bg") assert window_bg == LIGHT_COLORS.window_bg def test_adjust_color(self, clean_manager): """Test color adjustment.""" # Lighten a color result = clean_manager._adjust_color("#3498db", 20) assert result.startswith("#") assert len(result) == 7 # Darken a color result = clean_manager._adjust_color("#3498db", -20) assert result.startswith("#") assert len(result) == 7 def test_custom_stylesheet(self, clean_manager, tmp_path): """Test loading custom stylesheet.""" css_file = tmp_path / "custom.css" css_file.write_text("QPushButton { background-color: red; }") result = clean_manager.load_stylesheet_from_file(css_file) assert result is True assert "red" in clean_manager._custom_stylesheet def test_load_nonexistent_stylesheet(self, clean_manager): """Test loading non-existent stylesheet file.""" result = clean_manager.load_stylesheet_from_file(Path("/nonexistent/file.css")) assert result is False def test_theme_changed_signal(self, app, clean_manager, qtbot): """Test that theme_changed signal is emitted.""" signals = [] def on_theme_changed(mode): signals.append(mode) clean_manager.theme_changed.connect(on_theme_changed) clean_manager.set_theme(ThemeMode.DARK) assert len(signals) == 1 assert signals[0] == ThemeMode.DARK def test_set_custom_stylesheet(self, clean_manager): """Test setting custom stylesheet.""" custom_css = "QPushButton { background: red; }" clean_manager.set_custom_stylesheet(custom_css) assert clean_manager._custom_stylesheet == custom_css class TestThemeManagerSingleton: """Tests for the singleton pattern.""" def test_get_singleton(self): """Test getting singleton instance.""" manager = get_theme_manager() assert manager is not None assert isinstance(manager, ThemeManager) def test_singleton_persistence(self): """Test that singleton returns same instance.""" manager1 = get_theme_manager() manager2 = get_theme_manager() assert manager1 is manager2