""" Unit tests for example scripts. This test suite validates that all example scripts: 1. Can be imported without errors (syntax checks, import validation) 2. Have valid import statements 3. Can run their main functions without crashing (when applicable) This helps catch issues like: - Incorrect import paths - Missing dependencies - API breakages that affect examples """ import unittest import importlib.util import sys import os from pathlib import Path class TestExampleImports(unittest.TestCase): """Test that all example scripts can be imported successfully""" def setUp(self): """Set up test fixtures""" # Get the project root directory self.project_root = Path(__file__).parent.parent self.examples_dir = self.project_root / "examples" # Add project root to Python path if not already there if str(self.project_root) not in sys.path: sys.path.insert(0, str(self.project_root)) def _import_module_from_file(self, file_path: Path): """ Import a Python module from a file path. Args: file_path: Path to the Python file Returns: The imported module Raises: Any import errors that occur """ spec = importlib.util.spec_from_file_location(file_path.stem, file_path) if spec is None or spec.loader is None: raise ImportError(f"Could not load spec for {file_path}") module = importlib.util.module_from_spec(spec) sys.modules[file_path.stem] = module spec.loader.exec_module(module) return module def test_word_selection_highlighting_imports(self): """Test word_selection_highlighting.py can be imported""" example_file = self.examples_dir / "word_selection_highlighting.py" self.assertTrue(example_file.exists(), f"Example file not found: {example_file}") try: module = self._import_module_from_file(example_file) # Verify key components are available self.assertTrue(hasattr(module, 'draw_highlight')) self.assertTrue(hasattr(module, 'example_1_single_word_selection')) self.assertTrue(hasattr(module, 'example_2_range_selection')) self.assertTrue(hasattr(module, 'example_3_interactive_word_lookup')) self.assertTrue(hasattr(module, 'example_4_multi_word_annotation')) self.assertTrue(hasattr(module, 'example_5_link_highlighting')) except ImportError as e: self.fail(f"Failed to import word_selection_highlighting.py: {e}") def test_demo_pagination_imports(self): """Test demo_pagination.py can be imported""" example_file = self.examples_dir / "demo_pagination.py" self.assertTrue(example_file.exists(), f"Example file not found: {example_file}") try: module = self._import_module_from_file(example_file) self.assertTrue(hasattr(module, 'main')) except ImportError as e: self.fail(f"Failed to import demo_pagination.py: {e}") def test_demo_toc_overlay_imports(self): """Test demo_toc_overlay.py can be imported""" example_file = self.examples_dir / "demo_toc_overlay.py" self.assertTrue(example_file.exists(), f"Example file not found: {example_file}") try: module = self._import_module_from_file(example_file) self.assertTrue(hasattr(module, 'main')) except ImportError as e: self.fail(f"Failed to import demo_toc_overlay.py: {e}") def test_demo_settings_overlay_imports(self): """Test demo_settings_overlay.py can be imported""" example_file = self.examples_dir / "demo_settings_overlay.py" self.assertTrue(example_file.exists(), f"Example file not found: {example_file}") try: module = self._import_module_from_file(example_file) self.assertTrue(hasattr(module, 'main')) except ImportError as e: self.fail(f"Failed to import demo_settings_overlay.py: {e}") def test_library_reading_integration_imports(self): """Test library_reading_integration.py can be imported""" example_file = self.examples_dir / "library_reading_integration.py" self.assertTrue(example_file.exists(), f"Example file not found: {example_file}") try: module = self._import_module_from_file(example_file) self.assertTrue(hasattr(module, 'main')) self.assertTrue(hasattr(module, 'simulate_mode_transition_workflow')) except ImportError as e: self.fail(f"Failed to import library_reading_integration.py: {e}") def test_all_examples_have_correct_dreader_imports(self): """ Verify all example scripts use correct import paths for dreader classes. This test specifically checks that examples don't use outdated import paths like 'from dreader.application import' when they should use 'from dreader import'. """ # Get all Python files in examples directory example_files = list(self.examples_dir.glob("*.py")) problematic_imports = [] for example_file in example_files: # Skip __init__.py and other special files if example_file.name.startswith('_'): continue with open(example_file, 'r') as f: content = f.read() # Check for problematic import patterns if 'from pyWebLayout.io.gesture import' in content: problematic_imports.append( f"{example_file.name}: Uses 'from pyWebLayout.io.gesture import' " f"(should be 'from dreader import')" ) if 'from dreader.application import EbookReader' in content: # This is acceptable, but check if TouchEvent/GestureType are also imported correctly if 'from pyWebLayout.io.gesture import TouchEvent' in content: problematic_imports.append( f"{example_file.name}: Mixes dreader.application and pyWebLayout.io.gesture imports" ) if problematic_imports: self.fail( "Found problematic imports in example files:\n" + "\n".join(f" - {issue}" for issue in problematic_imports) ) class TestExampleFunctions(unittest.TestCase): """Test key functionality in example scripts""" def test_draw_highlight_function(self): """Test the draw_highlight function from word_selection_highlighting""" from PIL import Image # Import the module project_root = Path(__file__).parent.parent example_file = project_root / "examples" / "word_selection_highlighting.py" spec = importlib.util.spec_from_file_location("word_selection_highlighting", example_file) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) # Create a test image test_image = Image.new('RGBA', (100, 100), (255, 255, 255, 255)) # Test the draw_highlight function bounds = (10, 10, 50, 20) result = module.draw_highlight(test_image, bounds) # Verify the result is an image self.assertIsInstance(result, Image.Image) self.assertEqual(result.size, (100, 100)) self.assertEqual(result.mode, 'RGBA') class TestExampleDocumentation(unittest.TestCase): """Test that examples have proper documentation""" def test_all_examples_have_docstrings(self): """Verify all example scripts have module docstrings""" project_root = Path(__file__).parent.parent examples_dir = project_root / "examples" example_files = [ f for f in examples_dir.glob("*.py") if not f.name.startswith('_') and f.name not in ['__init__.py'] ] missing_docstrings = [] for example_file in example_files: spec = importlib.util.spec_from_file_location(example_file.stem, example_file) if spec is None or spec.loader is None: continue module = importlib.util.module_from_spec(spec) try: spec.loader.exec_module(module) if not module.__doc__ or len(module.__doc__.strip()) < 10: missing_docstrings.append(example_file.name) except: # If module can't be loaded, skip docstring check # (import test will catch the error) pass if missing_docstrings: self.fail( f"Examples missing proper docstrings: {', '.join(missing_docstrings)}" ) if __name__ == '__main__': unittest.main()