refactoring the mixin system
Python CI / test (push) Successful in 6m46s

This commit is contained in:
2025-11-08 08:08:02 +01:00
parent 49d4e551f8
commit ea93681aaf
13 changed files with 676 additions and 350 deletions
View File
+116
View File
@@ -0,0 +1,116 @@
"""
Test mixins for FontRegistry functionality.
Provides reusable test cases for any class that uses the FontRegistry mixin.
"""
from pyWebLayout.style import FontWeight, FontStyle, TextDecoration
class FontRegistryTestMixin:
"""
Mixin providing standard tests for FontRegistry behavior.
Classes using this mixin must implement:
- create_test_object() -> object with FontRegistry mixin
"""
def create_test_object(self):
"""
Create an instance of the object to test.
Must be implemented by test class.
"""
raise NotImplementedError("Test class must implement create_test_object()")
def test_font_caching(self):
"""Test that fonts with identical properties are cached and reused."""
obj = self.create_test_object()
# Create font twice with same properties
font1 = obj.get_or_create_font(font_size=14, colour=(255, 0, 0), weight=FontWeight.BOLD)
font2 = obj.get_or_create_font(font_size=14, colour=(255, 0, 0), weight=FontWeight.BOLD)
# Should return the same font object (cached)
self.assertIs(font1, font2, "Fonts with identical properties should be cached")
# Should only have one font in registry
self.assertEqual(len(obj._fonts), 1, "Registry should contain exactly one font")
def test_font_differentiation(self):
"""Test that fonts with different properties create separate instances."""
obj = self.create_test_object()
# Create fonts that differ in exactly one property each
base_params = {'colour': (0, 0, 0), 'weight': FontWeight.NORMAL}
font1 = obj.get_or_create_font(font_size=14, **base_params)
font2 = obj.get_or_create_font(font_size=16, **base_params) # Different size
base_params2 = {'font_size': 18, 'weight': FontWeight.NORMAL}
font3 = obj.get_or_create_font(colour=(255, 0, 0), **base_params2) # Different color
base_params3 = {'font_size': 20, 'colour': (100, 100, 100)}
font4 = obj.get_or_create_font(weight=FontWeight.BOLD, **base_params3) # Different weight
# All should be different objects
self.assertIsNot(font1, font2, "Fonts with different sizes should be distinct")
self.assertIsNot(font1, font3, "Fonts with different colors should be distinct")
self.assertIsNot(font1, font4, "Fonts with different weights should be distinct")
self.assertIsNot(font2, font3, "Fonts should be distinct")
self.assertIsNot(font2, font4, "Fonts should be distinct")
self.assertIsNot(font3, font4, "Fonts should be distinct")
# Should have 4 fonts in registry
self.assertEqual(len(obj._fonts), 4, "Should have 4 distinct fonts")
def test_font_properties(self):
"""Test that created fonts have the correct properties."""
obj = self.create_test_object()
font = obj.get_or_create_font(
font_size=18,
colour=(128, 64, 32),
weight=FontWeight.BOLD,
style=FontStyle.ITALIC,
decoration=TextDecoration.UNDERLINE
)
self.assertEqual(font.font_size, 18)
self.assertEqual(font.colour, (128, 64, 32))
self.assertEqual(font.weight, FontWeight.BOLD)
self.assertEqual(font.style, FontStyle.ITALIC)
self.assertEqual(font.decoration, TextDecoration.UNDERLINE)
class FontRegistryParentDelegationTestMixin:
"""
Test mixin for FontRegistry parent delegation functionality.
Classes using this mixin must implement:
- create_parent() -> parent object with FontRegistry
- create_child(parent) -> child object with FontRegistry and parent link
"""
def create_parent(self):
"""Create a parent object with FontRegistry. Must be implemented."""
raise NotImplementedError("Test class must implement create_parent()")
def create_child(self, parent):
"""Create a child object with parent reference. Must be implemented."""
raise NotImplementedError("Test class must implement create_child(parent)")
def test_parent_delegation(self):
"""Test that font creation delegates to parent when available."""
parent = self.create_parent()
child = self.create_child(parent)
# Create font through child
font = child.get_or_create_font(font_size=16, colour=(200, 100, 50))
# Font should be in parent's registry, not child's
self.assertEqual(len(parent._fonts), 1, "Font should be in parent registry")
self.assertEqual(len(child._fonts), 0, "Font should NOT be in child registry")
# Getting same font through child should return parent's font
font2 = child.get_or_create_font(font_size=16, colour=(200, 100, 50))
self.assertIs(font, font2, "Child should reuse parent's font")
+68
View File
@@ -0,0 +1,68 @@
"""
Test mixins for MetadataContainer functionality.
Provides reusable test cases for any class that uses the MetadataContainer mixin.
"""
class MetadataContainerTestMixin:
"""
Mixin providing standard tests for MetadataContainer behavior.
Classes using this mixin must implement:
- create_test_object() -> object with MetadataContainer mixin
"""
def create_test_object(self):
"""
Create an instance of the object to test.
Must be implemented by test class.
"""
raise NotImplementedError("Test class must implement create_test_object()")
def test_set_and_get_metadata(self):
"""Test basic metadata storage and retrieval."""
obj = self.create_test_object()
# Set various types of metadata
obj.set_metadata("string_key", "string_value")
obj.set_metadata("int_key", 42)
obj.set_metadata("list_key", [1, 2, 3])
obj.set_metadata("dict_key", {"nested": "value"})
# Verify retrieval
self.assertEqual(obj.get_metadata("string_key"), "string_value")
self.assertEqual(obj.get_metadata("int_key"), 42)
self.assertEqual(obj.get_metadata("list_key"), [1, 2, 3])
self.assertEqual(obj.get_metadata("dict_key"), {"nested": "value"})
def test_get_nonexistent_metadata(self):
"""Test that getting nonexistent metadata returns None."""
obj = self.create_test_object()
result = obj.get_metadata("nonexistent_key")
self.assertIsNone(result, "Nonexistent metadata should return None")
def test_update_metadata(self):
"""Test that metadata values can be updated."""
obj = self.create_test_object()
# Set initial value
obj.set_metadata("key", "initial")
self.assertEqual(obj.get_metadata("key"), "initial")
# Update value
obj.set_metadata("key", "updated")
self.assertEqual(obj.get_metadata("key"), "updated", "Metadata should be updateable")
def test_metadata_isolation(self):
"""Test that metadata is isolated between instances."""
obj1 = self.create_test_object()
obj2 = self.create_test_object()
obj1.set_metadata("key", "value1")
obj2.set_metadata("key", "value2")
self.assertEqual(obj1.get_metadata("key"), "value1")
self.assertEqual(obj2.get_metadata("key"), "value2")
self.assertNotEqual(obj1.get_metadata("key"), obj2.get_metadata("key"))