This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
Simplified unit tests for abstract document elements using test mixins.
|
||||
|
||||
This demonstrates how test mixins can eliminate duplication and simplify tests.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from pyWebLayout.abstract.document import Document, Chapter
|
||||
from tests.mixins.font_registry_tests import FontRegistryTestMixin, FontRegistryParentDelegationTestMixin
|
||||
from tests.mixins.metadata_tests import MetadataContainerTestMixin
|
||||
|
||||
|
||||
class TestDocumentFontRegistry(FontRegistryTestMixin, unittest.TestCase):
|
||||
"""Test FontRegistry behavior for Document - simplified with mixin."""
|
||||
|
||||
def create_test_object(self):
|
||||
"""Create a Document instance for testing."""
|
||||
return Document("Test Document", "en-US")
|
||||
|
||||
|
||||
class TestDocumentMetadata(MetadataContainerTestMixin, unittest.TestCase):
|
||||
"""Test MetadataContainer behavior for Document - simplified with mixin."""
|
||||
|
||||
def create_test_object(self):
|
||||
"""Create a Document instance for testing."""
|
||||
return Document("Test Document", "en-US")
|
||||
|
||||
|
||||
class TestChapterFontRegistry(FontRegistryTestMixin, unittest.TestCase):
|
||||
"""Test FontRegistry behavior for Chapter - simplified with mixin."""
|
||||
|
||||
def create_test_object(self):
|
||||
"""Create a Chapter instance for testing."""
|
||||
return Chapter("Test Chapter", level=1)
|
||||
|
||||
|
||||
class TestChapterFontRegistryParentDelegation(FontRegistryParentDelegationTestMixin, unittest.TestCase):
|
||||
"""Test FontRegistry parent delegation for Chapter - simplified with mixin."""
|
||||
|
||||
def create_parent(self):
|
||||
"""Create a Document as parent."""
|
||||
return Document("Parent Document", "en-US")
|
||||
|
||||
def create_child(self, parent):
|
||||
"""Create a Chapter with parent reference."""
|
||||
return Chapter("Child Chapter", level=1, parent=parent)
|
||||
|
||||
|
||||
class TestChapterMetadata(MetadataContainerTestMixin, unittest.TestCase):
|
||||
"""Test MetadataContainer behavior for Chapter - simplified with mixin."""
|
||||
|
||||
def create_test_object(self):
|
||||
"""Create a Chapter instance for testing."""
|
||||
return Chapter("Test Chapter", level=1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -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")
|
||||
@@ -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"))
|
||||
Reference in New Issue
Block a user