""" Test font utilities for ensuring consistent font usage across tests. This module provides utilities to guarantee that all tests use the same bundled font, preventing inconsistencies that can arise from different system fonts. """ import os from typing import Optional from PIL import ImageFont from pyWebLayout.style.fonts import Font, FontWeight, FontStyle, TextDecoration def get_bundled_font_path() -> Optional[str]: """ Get the path to the bundled DejaVuSans.ttf font. This function works from test directories by finding the font relative to the test file locations. Returns: str: Path to the bundled font file, or None if not found """ # Get the directory containing this test utility file current_dir = os.path.dirname(os.path.abspath(__file__)) # Navigate up to the project root (tests/utils -> tests -> root) project_root = os.path.dirname(os.path.dirname(current_dir)) # Path to the bundled font bundled_font_path = os.path.join( project_root, 'pyWebLayout', 'assets', 'fonts', 'DejaVuSans.ttf') if os.path.exists(bundled_font_path): return bundled_font_path # Alternative: try to find it relative to the pyWebLayout module try: import pyWebLayout module_dir = os.path.dirname(pyWebLayout.__file__) alt_font_path = os.path.join(module_dir, 'assets', 'fonts', 'DejaVuSans.ttf') if os.path.exists(alt_font_path): return alt_font_path except ImportError: pass return None def verify_bundled_font_available() -> bool: """ Verify that the bundled font is available and can be loaded. Returns: bool: True if the bundled font is available and loadable """ font_path = get_bundled_font_path() if not font_path: return False try: # Try to load the font with PIL to verify it's valid ImageFont.truetype(font_path, 16) return True except Exception: return False def create_test_font(font_size: int = 16, colour: tuple = (0, 0, 0), weight: FontWeight = FontWeight.NORMAL, style: FontStyle = FontStyle.NORMAL, decoration: TextDecoration = TextDecoration.NONE, background: Optional[tuple] = None, language: str = "en_EN", min_hyphenation_width: Optional[int] = None) -> Font: """ Create a Font object that uses the bundled font for consistent testing. This function ensures all tests use the same font file, preventing cross-system inconsistencies in text measurements and layout. Args: font_size: Size of the font in points colour: RGB color tuple for the text weight: Font weight (normal or bold) style: Font style (normal or italic) decoration: Text decoration (none, underline, or strikethrough) background: RGBA background color for the text language: Language code for hyphenation and text processing min_hyphenation_width: Minimum width in pixels for hyphenation Returns: Font: A Font object guaranteed to use the bundled font Raises: RuntimeError: If the bundled font cannot be found or loaded """ font_path = get_bundled_font_path() if not font_path: raise RuntimeError( "Bundled font (DejaVuSans.ttf) not found. " "Ensure the font exists in pyWebLayout/assets/fonts/" ) if not verify_bundled_font_available(): raise RuntimeError( f"Bundled font at {font_path} cannot be loaded. " "Font file may be corrupted or invalid." ) return Font( font_path=font_path, font_size=font_size, colour=colour, weight=weight, style=style, decoration=decoration, background=background, language=language, min_hyphenation_width=min_hyphenation_width ) def create_default_test_font() -> Font: """ Create a default Font object for testing with the bundled font. This is equivalent to Font() but guarantees the bundled font is used. Returns: Font: A default Font object using the bundled font """ return create_test_font() def ensure_consistent_font_in_tests(): """ Ensure that tests are using consistent fonts by checking availability. This function can be called in test setup to verify the font environment is properly configured. Raises: RuntimeError: If the bundled font is not available """ if not verify_bundled_font_available(): font_path = get_bundled_font_path() if font_path: raise RuntimeError( f"Bundled font found at {font_path} but cannot be loaded. " "Font file may be corrupted." ) else: raise RuntimeError( "Bundled font (DejaVuSans.ttf) not found. " "Ensure the font exists in pyWebLayout/assets/fonts/" ) # Convenience aliases get_test_font = create_default_test_font font_factory = create_test_font