pyWebLayout/tests/utils/test_fonts.py
Duncan Tourolle fdb3023919
Some checks failed
Python CI / test (push) Failing after 7m0s
fix all tests
2025-10-06 22:28:48 +02:00

165 lines
5.2 KiB
Python

"""
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
import sys
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
test_font = 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