251 lines
9.0 KiB
Python
251 lines
9.0 KiB
Python
"""
|
||
Unit tests for the new Page implementation to verify it meets the requirements:
|
||
1. Accepts a PageStyle that defines borders, line spacing and inter-block spacing
|
||
2. Makes an image canvas
|
||
3. Provides a method for accepting child objects
|
||
4. Provides methods for determining canvas size and border size
|
||
5. Has a method that calls render on all children
|
||
6. Has a method to query a point and determine which child it belongs to
|
||
"""
|
||
import unittest
|
||
import numpy as np
|
||
from PIL import Image, ImageDraw
|
||
from pyWebLayout.concrete.page import Page
|
||
from pyWebLayout.style.page_style import PageStyle
|
||
from pyWebLayout.style.fonts import Font
|
||
from pyWebLayout.core.base import Renderable, Queriable
|
||
|
||
|
||
class SimpleTestRenderable(Renderable, Queriable):
|
||
"""A simple test renderable for testing the page system"""
|
||
|
||
def __init__(self, text: str, size: tuple = (100, 50)):
|
||
self._text = text
|
||
self.size = size
|
||
self.origin = np.array([0, 0])
|
||
|
||
def render(self):
|
||
"""Render returns None - drawing is done via the page's draw object"""
|
||
return None
|
||
|
||
|
||
class TestPageImplementation(unittest.TestCase):
|
||
"""Test cases for the Page class implementation"""
|
||
|
||
def setUp(self):
|
||
"""Set up test fixtures"""
|
||
self.basic_style = PageStyle(
|
||
border_width=2,
|
||
border_color=(255, 0, 0),
|
||
line_spacing=8,
|
||
inter_block_spacing=20,
|
||
padding=(15, 15, 15, 15),
|
||
background_color=(240, 240, 240)
|
||
)
|
||
|
||
self.page_size = (800, 600)
|
||
|
||
def test_page_creation_with_style(self):
|
||
"""Test creating a page with a PageStyle"""
|
||
page = Page(size=self.page_size, style=self.basic_style)
|
||
|
||
self.assertEqual(page.size, self.page_size)
|
||
self.assertEqual(page.style, self.basic_style)
|
||
self.assertEqual(page.border_size, 2)
|
||
|
||
def test_page_creation_without_style(self):
|
||
"""Test creating a page without a PageStyle (should use defaults)"""
|
||
page = Page(size=self.page_size)
|
||
|
||
self.assertEqual(page.size, self.page_size)
|
||
self.assertIsNotNone(page.style)
|
||
|
||
def test_page_canvas_and_content_sizes(self):
|
||
"""Test that page correctly calculates canvas and content sizes"""
|
||
style = PageStyle(
|
||
border_width=5,
|
||
padding=(10, 20, 30, 40) # top, right, bottom, left
|
||
)
|
||
|
||
page = Page(size=self.page_size, style=style)
|
||
|
||
# Canvas size should be page size minus borders
|
||
expected_canvas_size = (790, 590) # 800-10, 600-10 (border on both sides)
|
||
self.assertEqual(page.canvas_size, expected_canvas_size)
|
||
|
||
# Content size should be canvas minus padding
|
||
expected_content_size = (730, 550) # 790-60, 590-40 (padding left+right, top+bottom)
|
||
self.assertEqual(page.content_size, expected_content_size)
|
||
|
||
def test_page_add_remove_children(self):
|
||
"""Test adding and removing children from the page"""
|
||
page = Page(size=self.page_size)
|
||
|
||
# Initially no children
|
||
self.assertEqual(len(page.children), 0)
|
||
|
||
# Add children
|
||
child1 = SimpleTestRenderable("Child 1")
|
||
child2 = SimpleTestRenderable("Child 2")
|
||
|
||
page.add_child(child1)
|
||
self.assertEqual(len(page.children), 1)
|
||
self.assertIn(child1, page.children)
|
||
|
||
page.add_child(child2)
|
||
self.assertEqual(len(page.children), 2)
|
||
self.assertIn(child2, page.children)
|
||
|
||
# Test method chaining
|
||
child3 = SimpleTestRenderable("Child 3")
|
||
result = page.add_child(child3)
|
||
self.assertIs(result, page) # Should return self for chaining
|
||
self.assertEqual(len(page.children), 3)
|
||
self.assertIn(child3, page.children)
|
||
|
||
# Remove childce you’ll notice is that responses don’t stream character-by-character like other providers. Instead, Claude Code processes your full request before sending back the complete response.
|
||
removed = page.remove_child(child2)
|
||
self.assertTrue(removed)
|
||
self.assertEqual(len(page.children), 2)
|
||
self.assertNotIn(child2, page.children)
|
||
|
||
# Try to remove non-existent child
|
||
removed = page.remove_child(child2)
|
||
self.assertFalse(removed)
|
||
|
||
# Clear all children
|
||
page.clear_children()
|
||
self.assertEqual(len(page.children), 0)
|
||
|
||
def test_page_render(self):
|
||
"""Test that page renders and creates a canvas"""
|
||
style = PageStyle(
|
||
border_width=2,
|
||
border_color=(255, 0, 0),
|
||
background_color=(255, 255, 255)
|
||
)
|
||
|
||
page = Page(size=(200, 150), style=style)
|
||
|
||
# Add a child
|
||
child = SimpleTestRenderable("Test child")
|
||
page.add_child(child)
|
||
|
||
# Render the page
|
||
image = page.render()
|
||
|
||
# Check that we got an image
|
||
self.assertIsInstance(image, Image.Image)
|
||
self.assertEqual(image.size, (200, 150))
|
||
self.assertEqual(image.mode, 'RGBA')
|
||
|
||
# Check that draw object is available
|
||
self.assertIsNotNone(page.draw)
|
||
|
||
def test_page_query_point(self):
|
||
"""Test querying points to find children"""
|
||
page = Page(size=(400, 300))
|
||
|
||
# Add children with known positions and sizes
|
||
child1 = SimpleTestRenderable("Child 1", (100, 50))
|
||
child2 = SimpleTestRenderable("Child 2", (80, 40))
|
||
|
||
page.add_child(child1).add_child(child2)
|
||
|
||
# Query points
|
||
# Point within first child
|
||
found_child = page.query_point((90, 30))
|
||
self.assertEqual(found_child, child1)
|
||
|
||
# Point within second child
|
||
found_child = page.query_point((30, 30))
|
||
self.assertEqual(found_child, child2)
|
||
|
||
# Point outside any child
|
||
found_child = page.query_point((300, 250))
|
||
self.assertIsNone(found_child)
|
||
|
||
def test_page_in_object(self):
|
||
"""Test that page correctly implements in_object"""
|
||
page = Page(size=(400, 300))
|
||
|
||
# Points within page bounds
|
||
self.assertTrue(page.in_object((0, 0)))
|
||
self.assertTrue(page.in_object((200, 150)))
|
||
self.assertTrue(page.in_object((399, 299)))
|
||
|
||
# Points outside page bounds
|
||
self.assertFalse(page.in_object((-1, 0)))
|
||
self.assertFalse(page.in_object((0, -1)))
|
||
self.assertFalse(page.in_object((400, 299)))
|
||
self.assertFalse(page.in_object((399, 300)))
|
||
|
||
def test_page_with_borders(self):
|
||
"""Test page rendering with borders"""
|
||
style = PageStyle(
|
||
border_width=3,
|
||
border_color=(128, 128, 128),
|
||
background_color=(255, 255, 255)
|
||
)
|
||
|
||
page = Page(size=(100, 100), style=style)
|
||
image = page.render()
|
||
|
||
# Check that image was created
|
||
self.assertIsInstance(image, Image.Image)
|
||
self.assertEqual(image.size, (100, 100))
|
||
|
||
# The border should be drawn but we can't easily test pixel values
|
||
# Just verify the image exists and has the right properties
|
||
|
||
def test_page_border_size_property(self):
|
||
"""Test that border_size property returns correct value"""
|
||
# Test with border
|
||
style_with_border = PageStyle(border_width=5)
|
||
page_with_border = Page(size=self.page_size, style=style_with_border)
|
||
self.assertEqual(page_with_border.border_size, 5)
|
||
|
||
# Test without border
|
||
style_no_border = PageStyle(border_width=0)
|
||
page_no_border = Page(size=self.page_size, style=style_no_border)
|
||
self.assertEqual(page_no_border.border_size, 0)
|
||
|
||
def test_page_style_properties(self):
|
||
"""Test that page correctly exposes style properties"""
|
||
page = Page(size=self.page_size, style=self.basic_style)
|
||
|
||
# Test that style properties are accessible
|
||
self.assertEqual(page.style.border_width, 2)
|
||
self.assertEqual(page.style.border_color, (255, 0, 0))
|
||
self.assertEqual(page.style.line_spacing, 8)
|
||
self.assertEqual(page.style.inter_block_spacing, 20)
|
||
self.assertEqual(page.style.padding, (15, 15, 15, 15))
|
||
self.assertEqual(page.style.background_color, (240, 240, 240))
|
||
|
||
def test_page_children_list_operations(self):
|
||
"""Test that children list behaves correctly"""
|
||
page = Page(size=self.page_size)
|
||
|
||
# Test that children is initially empty list
|
||
self.assertIsInstance(page.children, list)
|
||
self.assertEqual(len(page.children), 0)
|
||
|
||
# Test adding multiple children
|
||
children = [
|
||
SimpleTestRenderable(f"Child {i}")
|
||
for i in range(5)
|
||
]
|
||
|
||
for child in children:
|
||
page.add_child(child)
|
||
|
||
self.assertEqual(len(page.children), 5)
|
||
|
||
# Test that children are in the correct order
|
||
for i, child in enumerate(page.children):
|
||
self.assertEqual(child._text, f"Child {i}")
|
||
|
||
|
||
if __name__ == '__main__':
|
||
unittest.main()
|