Update coverage badges [skip ci]

This commit is contained in:
Gitea Action
2026-08-08 20:35:15 +00:00
commit 735face593
312 changed files with 91102 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
"""
Test utilities package for pyWebLayout.
Contains helper functions and utilities for testing.
"""
+143
View File
@@ -0,0 +1,143 @@
"""
Tests for the test font utilities module.
These tests verify that the bundled font system works correctly for consistent testing.
"""
import unittest
import os
from PIL import ImageFont
from tests.utils.test_fonts import (
get_bundled_font_path,
verify_bundled_font_available,
create_test_font,
create_default_test_font,
ensure_consistent_font_in_tests
)
from pyWebLayout.style.fonts import Font, FontWeight, FontStyle, TextDecoration
class TestFontUtilities(unittest.TestCase):
"""Test cases for font utility functions."""
def test_get_bundled_font_path_finds_font(self):
"""Test that get_bundled_font_path finds the bundled font."""
font_path = get_bundled_font_path()
self.assertIsNotNone(font_path, "Bundled font path should not be None")
self.assertTrue(
os.path.exists(font_path),
f"Font file should exist at {font_path}")
self.assertTrue(
font_path.endswith("DejaVuSans.ttf"),
"Font path should end with DejaVuSans.ttf")
def test_verify_bundled_font_available(self):
"""Test that the bundled font can be verified and loaded."""
self.assertTrue(verify_bundled_font_available(),
"Bundled font should be available and loadable")
def test_create_test_font_with_defaults(self):
"""Test creating a test font with default parameters."""
font = create_test_font()
self.assertIsInstance(font, Font)
self.assertEqual(font.font_size, 16)
self.assertEqual(font.colour, (0, 0, 0))
self.assertEqual(font.weight, FontWeight.NORMAL)
self.assertEqual(font.style, FontStyle.NORMAL)
self.assertEqual(font.decoration, TextDecoration.NONE)
def test_create_test_font_with_custom_parameters(self):
"""Test creating a test font with custom parameters."""
font = create_test_font(
font_size=24,
colour=(255, 0, 0),
weight=FontWeight.BOLD,
style=FontStyle.ITALIC,
decoration=TextDecoration.UNDERLINE
)
self.assertIsInstance(font, Font)
self.assertEqual(font.font_size, 24)
self.assertEqual(font.colour, (255, 0, 0))
self.assertEqual(font.weight, FontWeight.BOLD)
self.assertEqual(font.style, FontStyle.ITALIC)
self.assertEqual(font.decoration, TextDecoration.UNDERLINE)
def test_create_default_test_font(self):
"""Test creating a default test font."""
font = create_default_test_font()
self.assertIsInstance(font, Font)
self.assertEqual(font.font_size, 16)
self.assertEqual(font.colour, (0, 0, 0))
def test_ensure_consistent_font_in_tests_succeeds(self):
"""Test that ensure_consistent_font_in_tests runs without error when font is available."""
# This should not raise any exceptions if the font is properly available
try:
ensure_consistent_font_in_tests()
except RuntimeError:
self.fail(
"ensure_consistent_font_in_tests() raised RuntimeError when font should be available")
def test_bundled_font_loads_with_pil(self):
"""Test that the bundled font can be loaded directly with PIL."""
font_path = get_bundled_font_path()
self.assertIsNotNone(font_path)
# Test loading with different sizes
for size in [12, 16, 24, 48]:
with self.subTest(size=size):
pil_font = ImageFont.truetype(font_path, size)
self.assertIsNotNone(pil_font)
def test_font_metrics_consistency(self):
"""Test that font metrics are consistent between different Font objects using the same parameters."""
font1 = create_test_font(font_size=16)
font2 = create_test_font(font_size=16)
# Both fonts should have the same size
self.assertEqual(font1.font_size, font2.font_size)
# Test that text measurements are consistent
# This is a basic check - in real usage, text measurement consistency is
# what matters most
self.assertEqual(font1.font_size, font2.font_size)
def test_different_sizes_create_different_fonts(self):
"""Test that different font sizes create fonts with different metrics."""
small_font = create_test_font(font_size=12)
large_font = create_test_font(font_size=24)
self.assertNotEqual(small_font.font_size, large_font.font_size)
self.assertEqual(small_font.font_size, 12)
self.assertEqual(large_font.font_size, 24)
class TestFontPathResolution(unittest.TestCase):
"""Test cases for font path resolution from different locations."""
def test_font_path_is_absolute(self):
"""Test that the returned font path is absolute."""
font_path = get_bundled_font_path()
if font_path:
self.assertTrue(os.path.isabs(font_path), "Font path should be absolute")
def test_font_path_points_to_file(self):
"""Test that the font path points to a file, not a directory."""
font_path = get_bundled_font_path()
if font_path:
self.assertTrue(
os.path.isfile(font_path),
"Font path should point to a file")
def test_font_file_has_correct_extension(self):
"""Test that the font file has the expected .ttf extension."""
font_path = get_bundled_font_path()
if font_path:
self.assertTrue(
font_path.lower().endswith('.ttf'),
"Font file should have .ttf extension")
if __name__ == '__main__':
unittest.main()
+168
View File
@@ -0,0 +1,168 @@
"""
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