From df9738ab17967ab7c23c464dd3d3a3b117d146a3 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Tue, 5 Aug 2025 14:06:42 -0700 Subject: [PATCH] feat: enhance menu theming with comprehensive documentation and testing support --- docs/DOCUMENTATION_SUMMARY.md | 14 ++ docs/FEATURES.md | 1 + docs/MENU_THEMING.md | 105 ++++++++++++ docs/README.md | 11 +- docs/TESTING.md | 296 ++++++++++++++++++++++++++++++++++ scripts/README.md | 57 ++++++- scripts/test_menu_theming.py | 153 ++++++++++++++++++ scripts/verify_testing.py | 160 ++++++++++++++++++ src/main.py | 10 +- src/theme_manager.py | 65 ++++++++ tests/test_theme_manager.py | 126 +++++++++++++++ 11 files changed, 985 insertions(+), 13 deletions(-) create mode 100644 docs/MENU_THEMING.md create mode 100644 docs/TESTING.md create mode 100644 scripts/test_menu_theming.py create mode 100644 scripts/verify_testing.py create mode 100644 tests/test_theme_manager.py diff --git a/docs/DOCUMENTATION_SUMMARY.md b/docs/DOCUMENTATION_SUMMARY.md index 17a7a87..51ad123 100644 --- a/docs/DOCUMENTATION_SUMMARY.md +++ b/docs/DOCUMENTATION_SUMMARY.md @@ -48,6 +48,20 @@ docs/ ├── README.md # Documentation index and navigation guide ├── FEATURES.md # Complete feature documentation (includes UI/UX) ├── KEYBOARD_SHORTCUTS.md # Comprehensive shortcut reference +├── MENU_THEMING.md # Menu theming system documentation +├── TESTING.md # Comprehensive testing guide (NEW) +├── EXPORT_SYSTEM.md # Data export functionality +├── DEVELOPMENT.md # Development guidelines +├── CHANGELOG.md # Version history and changes +└── DOCUMENTATION_SUMMARY.md # This summary file +``` + +### Testing Documentation Consolidation (NEW) +- **Added**: `docs/TESTING.md` - Comprehensive testing guide +- **Updated**: `scripts/README.md` - Reorganized test script documentation +- **Added**: `tests/test_theme_manager.py` - Unit tests for menu theming +- **Updated**: `scripts/test_menu_theming.py` - Converted to interactive demo +- **Organized**: Clear separation of unit tests, integration tests, and demos ├── EXPORT_SYSTEM.md # Data export functionality ├── DEVELOPMENT.md # Development setup and testing ├── CHANGELOG.md # Version history and improvements diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 7f535ce..cf9007e 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -24,6 +24,7 @@ TheChart features a sophisticated theme system powered by ttkthemes, offering 8 - **Improved Tables**: Better selection highlighting and alternating row colors - **Settings System**: Comprehensive preferences with theme persistence - **Responsive Design**: Automatic layout adjustments and scaling +- **Menu Theming**: Complete menu integration with theme colors and hover effects ### ⌨️ Comprehensive Keyboard Shortcuts Professional keyboard shortcut system for efficient navigation and operation. diff --git a/docs/MENU_THEMING.md b/docs/MENU_THEMING.md new file mode 100644 index 0000000..8f48ff9 --- /dev/null +++ b/docs/MENU_THEMING.md @@ -0,0 +1,105 @@ +# Menu Theming Documentation + +## Overview + +TheChart application now supports full menu theming that integrates seamlessly with the application's theme system. All menus (File, Tools, Theme, Help) will automatically adopt colors that match the selected application theme. + +## Features + +### Automatic Theme Integration +- Menus automatically inherit colors from the current application theme +- Background colors are slightly adjusted to provide subtle visual distinction +- Hover effects use the theme's accent colors for consistency + +### Supported Menu Elements +- Main menu bar +- All dropdown menus (File, Tools, Theme, Help) +- Menu items and separators +- Hover/active states +- Disabled menu items + +### Theme Colors Applied + +For each theme, the following color properties are applied to menus: + +- **Background**: Slightly darker/lighter than the main theme background +- **Foreground**: Uses the theme's text color +- **Active Background**: Uses the theme's selection/accent color +- **Active Foreground**: Uses the theme's selection text color +- **Disabled Foreground**: Grayed out color for disabled items + +## Technical Implementation + +### ThemeManager Methods + +#### `get_menu_colors() -> dict[str, str]` +Returns a dictionary of colors specifically optimized for menu theming: +```python +{ + "bg": "#edeeef", # Menu background + "fg": "#5c616c", # Menu text + "active_bg": "#0078d4", # Hover background + "active_fg": "#ffffff", # Hover text + "disabled_fg": "#888888" # Disabled text +} +``` + +#### `configure_menu(menu: tk.Menu) -> None` +Applies theme colors to a specific menu widget: +```python +theme_manager.configure_menu(menubar) +theme_manager.configure_menu(file_menu) +``` + +### Automatic Updates + +When themes are changed using the Theme menu: +1. The new theme is applied to all UI components +2. The menu setup is refreshed (`_setup_menu()` is called) +3. All menus are automatically re-themed with the new colors + +## Usage Example + +```python +# Create menu +menubar = tk.Menu(root) +file_menu = tk.Menu(menubar, tearoff=0) + +# Apply theming +theme_manager.configure_menu(menubar) +theme_manager.configure_menu(file_menu) + +# Menus will now match the current theme +``` + +## Color Calculation + +The menu background color is automatically calculated based on the main theme: + +- **Light themes**: Menu background is made slightly darker than the main background +- **Dark themes**: Menu background is made slightly lighter than the main background + +This provides subtle visual distinction while maintaining theme consistency. + +## Supported Themes + +Menu theming works with all available themes: +- arc +- equilux +- adapta +- yaru +- ubuntu +- plastik +- breeze +- elegance + +## Testing + +A test script is available to verify menu theming functionality: + +```bash +cd /home/will/Code/thechart +.venv/bin/python scripts/test_menu_theming.py +``` + +This script creates a test window with menus that can be used to verify theming across different themes. diff --git a/docs/README.md b/docs/README.md index d09d4f0..10da090 100644 --- a/docs/README.md +++ b/docs/README.md @@ -53,7 +53,7 @@ Welcome to TheChart documentation! This guide will help you navigate the availab ### Development 1. **Setup**: See [DEVELOPMENT.md - Development Environment Setup](DEVELOPMENT.md#development-environment-setup) -2. **Testing**: See [DEVELOPMENT.md - Testing Framework](DEVELOPMENT.md#testing-framework) +2. **Testing**: See [TESTING.md](TESTING.md) - Comprehensive testing guide 3. **Architecture**: See [FEATURES.md - Technical Architecture](FEATURES.md#technical-architecture) 4. **Contributing**: See [DEVELOPMENT.md - Development Workflow](DEVELOPMENT.md#development-workflow) @@ -78,6 +78,8 @@ Welcome to TheChart documentation! This guide will help you navigate the availab - **UI/UX and Themes** → [FEATURES.md - Modern UI/UX System](FEATURES.md#-modern-uiux-system-new-in-v195) - **Feature Usage** → [FEATURES.md](FEATURES.md) - **Keyboard Shortcuts** → [KEYBOARD_SHORTCUTS.md](KEYBOARD_SHORTCUTS.md) +- **Menu Theming** → [MENU_THEMING.md](MENU_THEMING.md) +- **Testing** → [TESTING.md](TESTING.md) - **Data Export** → [EXPORT_SYSTEM.md](EXPORT_SYSTEM.md) - **Development** → [DEVELOPMENT.md](DEVELOPMENT.md) - **Version History** → [CHANGELOG.md](CHANGELOG.md) @@ -85,8 +87,8 @@ Welcome to TheChart documentation! This guide will help you navigate the availab ### By User Type - **End Users** → Start with [README.md](../README.md), then [FEATURES.md](FEATURES.md) - **Power Users** → [KEYBOARD_SHORTCUTS.md](KEYBOARD_SHORTCUTS.md) and [EXPORT_SYSTEM.md](EXPORT_SYSTEM.md) -- **Developers** → [DEVELOPMENT.md](DEVELOPMENT.md) and [FEATURES.md - Technical Architecture](FEATURES.md#technical-architecture) -- **Contributors** → All documentation, especially [DEVELOPMENT.md](DEVELOPMENT.md) +- **Developers** → [DEVELOPMENT.md](DEVELOPMENT.md), [TESTING.md](TESTING.md), and [FEATURES.md - Technical Architecture](FEATURES.md#technical-architecture) +- **Contributors** → All documentation, especially [DEVELOPMENT.md](DEVELOPMENT.md) and [TESTING.md](TESTING.md) ### By Task - **Install TheChart** → [README.md - Installation](../README.md#installation) @@ -95,7 +97,8 @@ Welcome to TheChart documentation! This guide will help you navigate the availab - **Add New Medicine** → [FEATURES.md - Modular Medicine System](FEATURES.md#-modular-medicine-system) - **Track Doses** → [FEATURES.md - Advanced Dose Tracking](FEATURES.md#-advanced-dose-tracking) - **Export Data** → [EXPORT_SYSTEM.md](EXPORT_SYSTEM.md) -- **Run Tests** → [DEVELOPMENT.md - Testing Framework](DEVELOPMENT.md#testing-framework) +- **Run Tests** → [TESTING.md](TESTING.md) - Comprehensive testing guide +- **Debug Issues** → [TESTING.md - Troubleshooting](TESTING.md#troubleshooting) - **Deploy Application** → [README.md - Deployment](../README.md#deployment) --- diff --git a/docs/TESTING.md b/docs/TESTING.md new file mode 100644 index 0000000..a2eaf09 --- /dev/null +++ b/docs/TESTING.md @@ -0,0 +1,296 @@ +# Testing Guide + +This document provides a comprehensive guide to testing in TheChart application. + +## Test Organization + +### Directory Structure + +``` +thechart/ +├── tests/ # Unit tests (pytest) +│ ├── test_theme_manager.py +│ ├── test_data_manager.py +│ ├── test_ui_manager.py +│ ├── test_graph_manager.py +│ └── ... +├── scripts/ # Integration tests & demos +│ ├── integration_test.py +│ ├── test_menu_theming.py +│ ├── test_note_saving.py +│ └── ... +``` + +## Test Categories + +### 1. Unit Tests (`/tests/`) + +**Purpose**: Test individual components in isolation +**Framework**: pytest +**Location**: `/tests/` directory + +#### Running Unit Tests +```bash +cd /home/will/Code/thechart +source .venv/bin/activate.fish +python -m pytest tests/ +``` + +#### Available Unit Tests +- `test_theme_manager.py` - Theme system and menu theming +- `test_data_manager.py` - Data persistence and CSV operations +- `test_ui_manager.py` - UI component functionality +- `test_graph_manager.py` - Graph generation and display +- `test_constants.py` - Application constants +- `test_logger.py` - Logging system +- `test_main.py` - Main application logic + +#### Writing Unit Tests +```python +# Example unit test structure +import unittest +import sys +import os + +# Add src to path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) + +from your_module import YourClass + +class TestYourClass(unittest.TestCase): + def setUp(self): + """Set up test fixtures.""" + pass + + def tearDown(self): + """Clean up after tests.""" + pass + + def test_functionality(self): + """Test specific functionality.""" + pass +``` + +### 2. Integration Tests (`/scripts/`) + +**Purpose**: Test complete workflows and system interactions +**Framework**: Custom test scripts +**Location**: `/scripts/` directory + +#### Available Integration Tests + +##### `integration_test.py` +Comprehensive export system test: +- Tests JSON, XML, PDF export formats +- Validates data integrity +- Tests file creation and cleanup +- No GUI dependencies + +```bash +.venv/bin/python scripts/integration_test.py +``` + +##### `test_note_saving.py` +Note persistence functionality: +- Tests note saving to CSV +- Validates special character handling +- Tests note retrieval + +##### `test_update_entry.py` +Entry modification functionality: +- Tests data update operations +- Validates date handling +- Tests duplicate prevention + +##### `test_keyboard_shortcuts.py` +Keyboard shortcut system: +- Tests key binding functionality +- Validates shortcut responses +- Tests keyboard event handling + +### 3. Interactive Demonstrations (`/scripts/`) + +**Purpose**: Visual and interactive testing of UI features +**Framework**: tkinter-based demos + +##### `test_menu_theming.py` +Interactive menu theming demonstration: +- Live theme switching +- Visual color display +- Real-time menu updates + +```bash +.venv/bin/python scripts/test_menu_theming.py +``` + +## Running Tests + +### Complete Test Suite +```bash +cd /home/will/Code/thechart +source .venv/bin/activate.fish + +# Run unit tests +python -m pytest tests/ -v + +# Run integration tests +python scripts/integration_test.py + +# Run specific feature tests +python scripts/test_note_saving.py +python scripts/test_update_entry.py +``` + +### Individual Test Categories +```bash +# Unit tests only +python -m pytest tests/ + +# Specific unit test file +python -m pytest tests/test_theme_manager.py -v + +# Integration test +python scripts/integration_test.py + +# Interactive demo +python scripts/test_menu_theming.py +``` + +### Test Runner Script +```bash +# Use the main test runner +python scripts/run_tests.py +``` + +## Test Environment Setup + +### Prerequisites +1. **Virtual Environment**: Ensure `.venv` is activated +2. **Dependencies**: All requirements installed via `uv` +3. **Test Data**: Main `thechart_data.csv` file present + +### Environment Activation +```bash +# Fish shell +source .venv/bin/activate.fish + +# Bash/Zsh +source .venv/bin/activate +``` + +## Writing New Tests + +### Unit Test Guidelines +1. Place in `/tests/` directory +2. Use pytest framework +3. Follow naming convention: `test_.py` +4. Include setup/teardown for fixtures +5. Test edge cases and error conditions + +### Integration Test Guidelines +1. Place in `/scripts/` directory +2. Test complete workflows +3. Include cleanup procedures +4. Document expected behavior +5. Handle GUI dependencies appropriately + +### Interactive Demo Guidelines +1. Place in `/scripts/` directory +2. Include clear instructions +3. Provide visual feedback +4. Allow easy theme/feature switching +5. Include exit mechanisms + +## Test Data Management + +### Test File Creation +- Use `tempfile` module for temporary files +- Clean up created files in teardown +- Don't commit test data to repository + +### CSV Test Data +- Most tests use main `thechart_data.csv` +- Some tests create temporary CSV files +- Integration tests may create export directories + +## Continuous Integration + +### Local Testing Workflow +```bash +# 1. Run linting +python -m flake8 src/ tests/ scripts/ + +# 2. Run unit tests +python -m pytest tests/ -v + +# 3. Run integration tests +python scripts/integration_test.py + +# 4. Run specific feature tests as needed +python scripts/test_note_saving.py +``` + +### Pre-commit Checklist +- [ ] All unit tests pass +- [ ] Integration tests pass +- [ ] New functionality has tests +- [ ] Documentation updated +- [ ] Code follows style guidelines + +## Troubleshooting + +### Common Issues + +#### Import Errors +```python +# Ensure src is in path +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) +``` + +#### GUI Test Issues +- Use `root.withdraw()` to hide test windows +- Ensure proper cleanup with `root.destroy()` +- Consider mocking GUI components for unit tests + +#### File Permission Issues +- Ensure test has write permissions +- Use temporary directories for test files +- Clean up files in teardown methods + +### Debug Mode +```bash +# Run with debug logging +python -c "import logging; logging.basicConfig(level=logging.DEBUG)" scripts/test_script.py +``` + +## Test Coverage + +### Current Coverage Areas +- ✅ Theme management and menu theming +- ✅ Data persistence and CSV operations +- ✅ Export functionality (JSON, XML, PDF) +- ✅ UI component initialization +- ✅ Graph generation +- ✅ Note saving and retrieval +- ✅ Entry update operations +- ✅ Keyboard shortcuts + +### Areas for Expansion +- Medicine and pathology management +- Settings persistence +- Error handling edge cases +- Performance testing +- UI interaction testing + +## Contributing Tests + +When contributing new tests: + +1. **Choose the right category**: Unit vs Integration vs Demo +2. **Follow naming conventions**: Clear, descriptive names +3. **Include documentation**: Docstrings and comments +4. **Test edge cases**: Not just happy path +5. **Clean up resources**: Temporary files, windows, etc. +6. **Update documentation**: Add to this guide and scripts/README.md diff --git a/scripts/README.md b/scripts/README.md index 89fafc3..ec2d332 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -1,6 +1,6 @@ # TheChart Scripts Directory -This directory contains testing and utility scripts for TheChart application. +This directory contains interactive demonstrations and utility scripts for TheChart application. ## Scripts Overview @@ -36,15 +36,62 @@ Tests entry update functionality. - Validates data modification operations - Tests date validation and duplicate handling -## Usage +#### `test_keyboard_shortcuts.py` +Tests keyboard shortcut functionality. +- Validates keyboard event handling +- Tests shortcut combinations and responses -All scripts should be run from the project root directory: +### Interactive Demonstrations + +#### `test_menu_theming.py` +Interactive demonstration of menu theming functionality. +- Live theme switching demonstration +- Visual display of theme colors +- Real-time menu color updates ```bash cd /home/will/Code/thechart -.venv/bin/python scripts/.py +.venv/bin/python scripts/test_menu_theming.py ``` +## Usage + +All scripts should be run from the project root directory using the virtual environment: + +```bash +cd /home/will/Code/thechart +source .venv/bin/activate.fish # For fish shell +# OR +source .venv/bin/activate # For bash/zsh + +python scripts/.py +``` + +## Test Organization + +### Unit Tests +Located in `/tests/` directory: +- `test_theme_manager.py` - Theme manager functionality tests +- `test_data_manager.py` - Data management tests +- `test_ui_manager.py` - UI component tests +- `test_graph_manager.py` - Graph functionality tests +- And more... + +Run unit tests with: +```bash +cd /home/will/Code/thechart +.venv/bin/python -m pytest tests/ +``` + +### Integration Tests +Located in `/scripts/` directory: +- `integration_test.py` - Export system integration test +- Feature-specific test scripts + +### Interactive Demos +Located in `/scripts/` directory: +- `test_menu_theming.py` - Menu theming demonstration + ## Test Data - Integration tests create temporary export files in `integration_test_exports/` (auto-cleaned) @@ -59,3 +106,5 @@ When adding new scripts: 3. Add proper docstrings and error handling 4. Update this README with script documentation 5. Follow the project's linting and formatting standards +6. For unit tests, place them in `/tests/` directory +7. For integration tests or demos, place them in `/scripts/` directory diff --git a/scripts/test_menu_theming.py b/scripts/test_menu_theming.py new file mode 100644 index 0000000..79dcfba --- /dev/null +++ b/scripts/test_menu_theming.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +"""Interactive demonstration of menu theming functionality.""" + +import logging +import os +import sys +import tkinter as tk + +# Add the src directory to the path so we can import the modules +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../src")) + +from theme_manager import ThemeManager + + +def demo_menu_theming(): + """Interactive demonstration of menu theming with different themes.""" + + # Set up logging + logging.basicConfig(level=logging.INFO) + logger = logging.getLogger(__name__) + + print("Menu Theming Interactive Demo") + print("=============================") + + # Create root window + root = tk.Tk() + root.title("Menu Theming Demo - TheChart") + root.geometry("500x400") + + # Initialize theme manager + theme_manager = ThemeManager(root, logger) + + # Create demo menubar using the new convenience method + menubar = theme_manager.create_themed_menu(root) + root.config(menu=menubar) + + # Create submenus + file_menu = theme_manager.create_themed_menu(menubar, tearoff=0) + theme_menu = theme_manager.create_themed_menu(menubar, tearoff=0) + help_menu = theme_manager.create_themed_menu(menubar, tearoff=0) + + menubar.add_cascade(label="File", menu=file_menu) + menubar.add_cascade(label="Theme", menu=theme_menu) + menubar.add_cascade(label="Help", menu=help_menu) + + # Populate file menu + file_menu.add_command(label="Demo Item 1") + file_menu.add_command(label="Demo Item 2") + file_menu.add_separator() + file_menu.add_command(label="Exit Demo", command=root.quit) + + # Populate help menu + help_menu.add_command( + label="About Demo", + command=lambda: tk.messagebox.showinfo( + "About", "Interactive menu theming demonstration for TheChart" + ), + ) + + # Theme information display + theme_info_frame = tk.Frame(root, relief="ridge", bd=2) + theme_info_frame.pack(fill="x", padx=20, pady=10) + + current_theme_label = tk.Label( + theme_info_frame, + text=f"Current Theme: {theme_manager.get_current_theme().title()}", + font=("Arial", 12, "bold"), + ) + current_theme_label.pack(pady=5) + + colors_display = tk.Text(theme_info_frame, height=6, wrap="word") + colors_display.pack(fill="x", padx=10, pady=5) + + def update_theme_display(): + """Update the theme information display.""" + current_theme_label.config( + text=f"Current Theme: {theme_manager.get_current_theme().title()}" + ) + + menu_colors = theme_manager.get_menu_colors() + colors_text = "Current Menu Colors:\n" + for key, value in menu_colors.items(): + colors_text += f" {key}: {value}\n" + + colors_display.delete(1.0, tk.END) + colors_display.insert(1.0, colors_text) + + # Function to apply theme and update displays + def apply_theme_and_update(theme_name): + """Apply theme and update all displays.""" + print(f"Switching to theme: {theme_name}") + if theme_manager.apply_theme(theme_name): + # Re-theme all menus + theme_manager.configure_menu(menubar) + theme_manager.configure_menu(file_menu) + theme_manager.configure_menu(theme_menu) + theme_manager.configure_menu(help_menu) + + # Update display + update_theme_display() + print(f" ✓ Successfully applied {theme_name} theme") + else: + print(f" ✗ Failed to apply {theme_name} theme") + + # Create theme selection menu + available_themes = theme_manager.get_available_themes() + current_theme = theme_manager.get_current_theme() + + for theme in available_themes: + theme_menu.add_radiobutton( + label=theme.title(), + command=lambda t=theme: apply_theme_and_update(t), + value=theme == current_theme, + ) + + # Instructions + instructions_frame = tk.Frame(root) + instructions_frame.pack(fill="both", expand=True, padx=20, pady=10) + + tk.Label( + instructions_frame, + text="Menu Theming Demonstration", + font=("Arial", 16, "bold"), + ).pack(pady=10) + + instructions_text = """ +Instructions: +1. Use the Theme menu to switch between different themes +2. Observe how menu colors change to match each theme +3. Try the File and Help menus to see the color effects +4. Menu backgrounds, text, and hover effects all update automatically + +Available themes: """ + ", ".join([t.title() for t in available_themes]) + + tk.Label( + instructions_frame, + text=instructions_text, + justify="left", + wraplength=450, + ).pack(pady=10) + + # Initialize display + update_theme_display() + + print(f"Demo window opened with {len(available_themes)} available themes.") + print("Try the Theme menu to see different color schemes!") + + # Show the window + root.mainloop() + + +if __name__ == "__main__": + demo_menu_theming() diff --git a/scripts/verify_testing.py b/scripts/verify_testing.py new file mode 100644 index 0000000..5df3810 --- /dev/null +++ b/scripts/verify_testing.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +"""Quick verification script for consolidated testing structure.""" + +import os +import subprocess +import sys + + +def run_command(cmd, description): + """Run a command and return the result.""" + print(f"\n🔍 {description}") + print(f"Command: {cmd}") + print("-" * 50) + + try: + result = subprocess.run( + cmd, + shell=True, + capture_output=True, + text=True, + cwd="/home/will/Code/thechart", + ) + if result.returncode == 0: + print("✅ SUCCESS") + if result.stdout: + print(result.stdout[:500]) # First 500 chars + else: + print("❌ FAILED") + if result.stderr: + print(result.stderr[:500]) + return result.returncode == 0 + except Exception as e: + print(f"❌ ERROR: {e}") + return False + + +def verify_test_structure(): + """Verify the consolidated test structure.""" + print("🧪 TheChart Testing Structure Verification") + print("=" * 50) + + # Check if we're in the right directory + if not os.path.exists("src/main.py"): + print("❌ Please run this script from the project root directory") + return False + + # Check test directories exist + test_dirs = ["tests", "scripts"] + for dir_name in test_dirs: + if os.path.exists(dir_name): + print(f"✅ Directory {dir_name}/ exists") + else: + print(f"❌ Directory {dir_name}/ missing") + return False + + # Check key test files exist + test_files = [ + "tests/test_theme_manager.py", + "scripts/test_menu_theming.py", + "scripts/integration_test.py", + "docs/TESTING.md", + ] + + for file_path in test_files: + if os.path.exists(file_path): + print(f"✅ File {file_path} exists") + else: + print(f"❌ File {file_path} missing") + return False + + # Check virtual environment + if os.path.exists(".venv/bin/python"): + print("✅ Virtual environment found") + else: + print("❌ Virtual environment not found") + return False + + print("\n📋 Test Structure Summary:") + print("Unit Tests: tests/") + print("Integration Tests: scripts/") + print("Interactive Demos: scripts/") + print("Documentation: docs/TESTING.md") + + return True + + +def run_test_verification(): + """Run basic test verification.""" + print("\n🚀 Running Test Verification") + print("=" * 50) + + success_count = 0 + total_tests = 0 + + # Test 1: Unit test syntax check + total_tests += 1 + if run_command( + "source .venv/bin/activate.fish && " + "python -m py_compile tests/test_theme_manager.py", + "Unit test syntax check", + ): + success_count += 1 + + # Test 2: Integration test syntax check + total_tests += 1 + if run_command( + "source .venv/bin/activate.fish && " + "python -m py_compile scripts/integration_test.py", + "Integration test syntax check", + ): + success_count += 1 + + # Test 3: Demo script syntax check + total_tests += 1 + if run_command( + "source .venv/bin/activate.fish && " + "python -m py_compile scripts/test_menu_theming.py", + "Demo script syntax check", + ): + success_count += 1 + + # Test 4: Check if pytest is available + total_tests += 1 + pytest_cmd = ( + "source .venv/bin/activate.fish && " + "python -c 'import pytest; print(f\"pytest version: {pytest.__version__}\")'" + ) + if run_command(pytest_cmd, "Pytest availability check"): + success_count += 1 + + print(f"\n📊 Test Verification Results: {success_count}/{total_tests} passed") + + if success_count == total_tests: + print("✅ All verification tests passed!") + print("\n🎯 Next Steps:") + print("1. Run unit tests: python -m pytest tests/ -v") + print("2. Run integration test: python scripts/integration_test.py") + print("3. Try interactive demo: python scripts/test_menu_theming.py") + else: + print("❌ Some verification tests failed. Check the output above.") + + return success_count == total_tests + + +if __name__ == "__main__": + print("🧪 TheChart Consolidated Testing Verification") + print("=" * 60) + + # Verify structure + if not verify_test_structure(): + print("\n❌ Test structure verification failed") + sys.exit(1) + + # Run verification tests + if not run_test_verification(): + print("\n❌ Test verification failed") + sys.exit(1) + + print("\n🎉 All verification checks passed!") + print("📚 See docs/TESTING.md for complete testing guide") diff --git a/src/main.py b/src/main.py index 071604f..5d072a9 100644 --- a/src/main.py +++ b/src/main.py @@ -178,11 +178,11 @@ class MedTrackerApp: def _setup_menu(self) -> None: """Set up the menu bar.""" - menubar = tk.Menu(self.root) + menubar = self.theme_manager.create_themed_menu(self.root) self.root.config(menu=menubar) # File menu - file_menu = tk.Menu(menubar, tearoff=0) + file_menu = self.theme_manager.create_themed_menu(menubar, tearoff=0) menubar.add_cascade(label="File", menu=file_menu) file_menu.add_command( label="Export Data...", @@ -195,7 +195,7 @@ class MedTrackerApp: ) # Tools menu - tools_menu = tk.Menu(menubar, tearoff=0) + tools_menu = self.theme_manager.create_themed_menu(menubar, tearoff=0) menubar.add_cascade(label="Tools", menu=tools_menu) tools_menu.add_command( label="Manage Pathologies...", @@ -216,7 +216,7 @@ class MedTrackerApp: ) # Theme menu - theme_menu = tk.Menu(menubar, tearoff=0) + theme_menu = self.theme_manager.create_themed_menu(menubar, tearoff=0) menubar.add_cascade(label="Theme", menu=theme_menu) # Add quick theme options @@ -237,7 +237,7 @@ class MedTrackerApp: ) # Help menu - help_menu = tk.Menu(menubar, tearoff=0) + help_menu = self.theme_manager.create_themed_menu(menubar, tearoff=0) menubar.add_cascade(label="Help", menu=help_menu) help_menu.add_command( label="Settings...", diff --git a/src/theme_manager.py b/src/theme_manager.py index e91a911..3fe738e 100644 --- a/src/theme_manager.py +++ b/src/theme_manager.py @@ -213,6 +213,71 @@ class ThemeManager: except Exception as e: self.logger.error(f"Failed to configure custom styles: {e}") + def get_menu_colors(self) -> dict[str, str]: + """Get colors specifically for menu theming.""" + colors = self.get_theme_colors() + + # Use slightly different colors for menus to make them stand out + try: + # For menu background, use a slightly darker/lighter shade + if colors["bg"].startswith("#"): + rgb = tuple(int(colors["bg"][i : i + 2], 16) for i in (1, 3, 5)) + if sum(rgb) > 384: # Light theme - make menu slightly darker + menu_bg = ( + f"#{max(0, rgb[0] - 8):02x}" + f"{max(0, rgb[1] - 8):02x}" + f"{max(0, rgb[2] - 8):02x}" + ) + else: # Dark theme - make menu slightly lighter + menu_bg = ( + f"#{min(255, rgb[0] + 15):02x}" + f"{min(255, rgb[1] + 15):02x}" + f"{min(255, rgb[2] + 15):02x}" + ) + else: + menu_bg = colors["bg"] + except (ValueError, IndexError): + menu_bg = colors["bg"] + + return { + "bg": menu_bg, + "fg": colors["fg"], + "active_bg": colors["select_bg"], + "active_fg": colors["select_fg"], + "disabled_fg": colors.get("disabled_fg", "#888888"), + } + + def configure_menu(self, menu: "tk.Menu") -> None: + """Apply theme colors to a menu widget.""" + try: + menu_colors = self.get_menu_colors() + + menu.configure( + background=menu_colors["bg"], + foreground=menu_colors["fg"], + activebackground=menu_colors["active_bg"], + activeforeground=menu_colors["active_fg"], + disabledforeground=menu_colors["disabled_fg"], + relief="flat", + borderwidth=1, + ) + + self.logger.debug(f"Applied theme to menu: {menu_colors}") + + except Exception as e: + self.logger.error(f"Failed to configure menu theme: {e}") + + def create_themed_menu(self, parent: "tk.Widget", **kwargs) -> "tk.Menu": + """Create a new menu with theme colors already applied.""" + try: + menu = tk.Menu(parent, **kwargs) + self.configure_menu(menu) + return menu + except Exception as e: + self.logger.error(f"Failed to create themed menu: {e}") + # Fallback to regular menu if theming fails + return tk.Menu(parent, **kwargs) + def configure_widget_style(self, widget: tk.Widget, style_name: str) -> None: """Apply a specific style to a widget.""" try: diff --git a/tests/test_theme_manager.py b/tests/test_theme_manager.py new file mode 100644 index 0000000..c2aca94 --- /dev/null +++ b/tests/test_theme_manager.py @@ -0,0 +1,126 @@ +""" +Tests for theme manager menu functionality. +""" +import os +import sys +import unittest +from unittest.mock import Mock, patch +import tkinter as tk + +# Add src to path for imports +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) + +from theme_manager import ThemeManager + + +class TestThemeManagerMenu(unittest.TestCase): + """Test cases for theme manager menu functionality.""" + + def setUp(self): + """Set up test fixtures.""" + self.root = tk.Tk() + self.root.withdraw() # Hide the window during testing + self.mock_logger = Mock() + self.theme_manager = ThemeManager(self.root, self.mock_logger) + + def tearDown(self): + """Clean up after tests.""" + if self.root: + self.root.destroy() + + def test_get_menu_colors(self): + """Test that get_menu_colors returns valid color dictionary.""" + colors = self.theme_manager.get_menu_colors() + + # Check that all required keys are present + required_keys = ["bg", "fg", "active_bg", "active_fg", "disabled_fg"] + for key in required_keys: + self.assertIn(key, colors) + + # Check that colors are valid hex strings or named colors + for key, color in colors.items(): + self.assertIsInstance(color, str) + self.assertTrue(len(color) > 0) + + def test_configure_menu(self): + """Test that configure_menu applies theme to menu widget.""" + menu = tk.Menu(self.root) + + # Configure the menu + self.theme_manager.configure_menu(menu) + + # Check that menu configuration was called + # Note: We can't directly test the visual appearance, but we can + # verify that no exceptions were raised + self.assertIsNotNone(menu) + + def test_create_themed_menu(self): + """Test that create_themed_menu creates and themes a menu.""" + menu = self.theme_manager.create_themed_menu(self.root, tearoff=0) + + # Check that a menu was created + self.assertIsInstance(menu, tk.Menu) + + # Check that the menu has the tearoff option set + self.assertEqual(menu['tearoff'], 0) + + def test_menu_colors_consistency(self): + """Test that menu colors are consistent across theme changes.""" + original_colors = self.theme_manager.get_menu_colors() + + # Try to apply a different theme + available_themes = self.theme_manager.get_available_themes() + if len(available_themes) > 1: + # Apply a different theme + other_theme = available_themes[1] if available_themes[0] == self.theme_manager.current_theme else available_themes[0] + self.theme_manager.apply_theme(other_theme) + + # Get new colors + new_colors = self.theme_manager.get_menu_colors() + + # Colors should still have the same structure + self.assertEqual(set(original_colors.keys()), set(new_colors.keys())) + + # Colors might be different (which is expected) + # Just ensure they're still valid + for color in new_colors.values(): + self.assertIsInstance(color, str) + self.assertTrue(len(color) > 0) + + @patch('tkinter.Menu') + def test_create_themed_menu_error_handling(self, mock_menu_class): + """Test that create_themed_menu handles errors gracefully.""" + # Make the Menu constructor raise an exception + mock_menu_class.side_effect = Exception("Test error") + + # This should not raise an exception but return a fallback menu + menu = self.theme_manager.create_themed_menu(self.root) + + # The method should still return something (fallback behavior) + self.assertIsNotNone(menu) + + def test_menu_theme_integration(self): + """Test complete menu theming workflow.""" + # Create a menu structure similar to the main application + menubar = self.theme_manager.create_themed_menu(self.root) + file_menu = self.theme_manager.create_themed_menu(menubar, tearoff=0) + theme_menu = self.theme_manager.create_themed_menu(menubar, tearoff=0) + + # Add some menu items + file_menu.add_command(label="Test Item 1") + file_menu.add_separator() + file_menu.add_command(label="Test Item 2") + + # Add theme selection items + available_themes = self.theme_manager.get_available_themes() + for theme in available_themes: + theme_menu.add_radiobutton(label=theme.title()) + + # Verify structure was created successfully + self.assertIsInstance(menubar, tk.Menu) + self.assertIsInstance(file_menu, tk.Menu) + self.assertIsInstance(theme_menu, tk.Menu) + + +if __name__ == '__main__': + unittest.main()