pyWebLayout/tests/test_concrete_page.py
Duncan Tourolle 210358913a
All checks were successful
Python CI / test (push) Successful in 4m50s
added tests to ensure border is respected.
2025-06-08 17:29:42 +02:00

757 lines
32 KiB
Python

"""
Unit tests for pyWebLayout.concrete.page module.
Tests the Container and Page classes for layout and rendering functionality.
"""
import unittest
import numpy as np
from PIL import Image
from unittest.mock import Mock, patch, MagicMock
from pyWebLayout.concrete.page import Container, Page
from pyWebLayout.concrete.box import Box
from pyWebLayout.style.layout import Alignment
class TestContainer(unittest.TestCase):
"""Test cases for the Container class"""
def setUp(self):
"""Set up test fixtures"""
self.origin = (0, 0)
self.size = (400, 300)
self.callback = Mock()
# Create mock child elements
self.mock_child1 = Mock()
self.mock_child1._size = np.array([100, 50])
self.mock_child1._origin = np.array([0, 0])
self.mock_child1.render.return_value = Image.new('RGBA', (100, 50), (255, 0, 0, 255))
self.mock_child2 = Mock()
self.mock_child2._size = np.array([120, 60])
self.mock_child2._origin = np.array([0, 0])
self.mock_child2.render.return_value = Image.new('RGBA', (120, 60), (0, 255, 0, 255))
def test_container_initialization_basic(self):
"""Test basic container initialization"""
container = Container(self.origin, self.size)
np.testing.assert_array_equal(container._origin, np.array(self.origin))
np.testing.assert_array_equal(container._size, np.array(self.size))
self.assertEqual(container._direction, 'vertical')
self.assertEqual(container._spacing, 5)
self.assertEqual(len(container._children), 0)
self.assertEqual(container._padding, (10, 10, 10, 10))
self.assertEqual(container._halign, Alignment.CENTER)
self.assertEqual(container._valign, Alignment.CENTER)
def test_container_initialization_with_params(self):
"""Test container initialization with custom parameters"""
custom_direction = 'horizontal'
custom_spacing = 15
custom_padding = (5, 8, 5, 8)
container = Container(
self.origin, self.size,
direction=custom_direction,
spacing=custom_spacing,
callback=self.callback,
halign=Alignment.LEFT,
valign=Alignment.TOP,
padding=custom_padding
)
self.assertEqual(container._direction, custom_direction)
self.assertEqual(container._spacing, custom_spacing)
self.assertEqual(container._callback, self.callback)
self.assertEqual(container._halign, Alignment.LEFT)
self.assertEqual(container._valign, Alignment.TOP)
self.assertEqual(container._padding, custom_padding)
def test_add_child(self):
"""Test adding child elements"""
container = Container(self.origin, self.size)
result = container.add_child(self.mock_child1)
self.assertEqual(len(container._children), 1)
self.assertEqual(container._children[0], self.mock_child1)
self.assertEqual(result, container) # Should return self for chaining
def test_add_multiple_children(self):
"""Test adding multiple child elements"""
container = Container(self.origin, self.size)
container.add_child(self.mock_child1)
container.add_child(self.mock_child2)
self.assertEqual(len(container._children), 2)
self.assertEqual(container._children[0], self.mock_child1)
self.assertEqual(container._children[1], self.mock_child2)
def test_layout_vertical_centered(self):
"""Test vertical layout with center alignment"""
container = Container(self.origin, self.size, direction='vertical', halign=Alignment.CENTER)
container.add_child(self.mock_child1)
container.add_child(self.mock_child2)
container.layout()
# Check that children have been positioned
# First child should be at top padding
expected_x1 = 10 + (380 - 100) // 2 # padding + centered in available width
expected_y1 = 10 # top padding
np.testing.assert_array_equal(self.mock_child1._origin, np.array([expected_x1, expected_y1]))
# Second child should be below first child + spacing
expected_x2 = 10 + (380 - 120) // 2 # padding + centered in available width
expected_y2 = 10 + 50 + 5 # top padding + first child height + spacing
np.testing.assert_array_equal(self.mock_child2._origin, np.array([expected_x2, expected_y2]))
def test_layout_vertical_left_aligned(self):
"""Test vertical layout with left alignment"""
container = Container(self.origin, self.size, direction='vertical', halign=Alignment.LEFT)
container.add_child(self.mock_child1)
container.add_child(self.mock_child2)
container.layout()
# Both children should be left-aligned
expected_x = 10 # left padding
np.testing.assert_array_equal(self.mock_child1._origin, np.array([expected_x, 10]))
np.testing.assert_array_equal(self.mock_child2._origin, np.array([expected_x, 65]))
def test_layout_vertical_right_aligned(self):
"""Test vertical layout with right alignment"""
container = Container(self.origin, self.size, direction='vertical', halign=Alignment.RIGHT)
container.add_child(self.mock_child1)
container.add_child(self.mock_child2)
container.layout()
# Children should be right-aligned
expected_x1 = 10 + 380 - 100 # left padding + available width - child width
expected_x2 = 10 + 380 - 120
np.testing.assert_array_equal(self.mock_child1._origin, np.array([expected_x1, 10]))
np.testing.assert_array_equal(self.mock_child2._origin, np.array([expected_x2, 65]))
def test_layout_horizontal_centered(self):
"""Test horizontal layout with center alignment"""
container = Container(self.origin, self.size, direction='horizontal', valign=Alignment.CENTER)
container.add_child(self.mock_child1)
container.add_child(self.mock_child2)
container.layout()
# Children should be positioned horizontally
expected_x1 = 10 # left padding
expected_x2 = 10 + 100 + 5 # left padding + first child width + spacing
# Vertically centered
expected_y1 = 10 + (280 - 50) // 2 # top padding + centered in available height
expected_y2 = 10 + (280 - 60) // 2
np.testing.assert_array_equal(self.mock_child1._origin, np.array([expected_x1, expected_y1]))
np.testing.assert_array_equal(self.mock_child2._origin, np.array([expected_x2, expected_y2]))
def test_layout_horizontal_top_aligned(self):
"""Test horizontal layout with top alignment"""
container = Container(self.origin, self.size, direction='horizontal', valign=Alignment.TOP)
container.add_child(self.mock_child1)
container.add_child(self.mock_child2)
container.layout()
# Both children should be top-aligned
expected_y = 10 # top padding
np.testing.assert_array_equal(self.mock_child1._origin, np.array([10, expected_y]))
np.testing.assert_array_equal(self.mock_child2._origin, np.array([115, expected_y]))
def test_layout_horizontal_bottom_aligned(self):
"""Test horizontal layout with bottom alignment"""
container = Container(self.origin, self.size, direction='horizontal', valign=Alignment.BOTTOM)
container.add_child(self.mock_child1)
container.add_child(self.mock_child2)
container.layout()
# Children should be bottom-aligned
expected_y1 = 10 + 280 - 50 # top padding + available height - child height
expected_y2 = 10 + 280 - 60
np.testing.assert_array_equal(self.mock_child1._origin, np.array([10, expected_y1]))
np.testing.assert_array_equal(self.mock_child2._origin, np.array([115, expected_y2]))
def test_layout_empty_container(self):
"""Test layout with no children"""
container = Container(self.origin, self.size)
# Should not raise an error
container.layout()
self.assertEqual(len(container._children), 0)
def test_layout_with_layoutable_children(self):
"""Test layout with children that are also layoutable"""
# Create a mock child that implements Layoutable
mock_layoutable_child = Mock()
mock_layoutable_child._size = np.array([80, 40])
mock_layoutable_child._origin = np.array([0, 0])
# Make it look like a Layoutable by adding layout method
from pyWebLayout.core.base import Layoutable
mock_layoutable_child.__class__ = type('MockLayoutable', (Mock, Layoutable), {})
mock_layoutable_child.layout = Mock()
container = Container(self.origin, self.size)
container.add_child(mock_layoutable_child)
container.layout()
# Child's layout method should have been called
mock_layoutable_child.layout.assert_called_once()
def test_render_empty_container(self):
"""Test rendering empty container"""
container = Container(self.origin, self.size)
result = container.render()
self.assertIsInstance(result, Image.Image)
self.assertEqual(result.size, tuple(self.size))
def test_render_with_children(self):
"""Test rendering container with children"""
container = Container(self.origin, self.size)
container.add_child(self.mock_child1)
container.add_child(self.mock_child2)
result = container.render()
self.assertIsInstance(result, Image.Image)
self.assertEqual(result.size, tuple(self.size))
# Children should have been rendered
self.mock_child1.render.assert_called_once()
self.mock_child2.render.assert_called_once()
def test_render_calls_layout(self):
"""Test that render calls layout"""
container = Container(self.origin, self.size)
container.add_child(self.mock_child1)
with patch.object(container, 'layout') as mock_layout:
result = container.render()
mock_layout.assert_called_once()
def test_custom_spacing(self):
"""Test container with custom spacing"""
custom_spacing = 20
container = Container(self.origin, self.size, spacing=custom_spacing)
container.add_child(self.mock_child1)
container.add_child(self.mock_child2)
container.layout()
# Second child should be positioned with custom spacing
expected_y2 = 10 + 50 + custom_spacing # top padding + first child height + custom spacing
self.assertEqual(self.mock_child2._origin[1], expected_y2)
class TestPage(unittest.TestCase):
"""Test cases for the Page class"""
def setUp(self):
"""Set up test fixtures"""
self.page_size = (800, 600)
self.background_color = (255, 255, 255)
# Create mock child elements
self.mock_child1 = Mock()
self.mock_child1._size = np.array([200, 100])
self.mock_child1._origin = np.array([0, 0])
self.mock_child1.render.return_value = Image.new('RGBA', (200, 100), (255, 0, 0, 255))
self.mock_child2 = Mock()
self.mock_child2._size = np.array([150, 80])
self.mock_child2._origin = np.array([0, 0])
self.mock_child2.render.return_value = Image.new('RGBA', (150, 80), (0, 255, 0, 255))
def test_page_initialization_basic(self):
"""Test basic page initialization"""
page = Page()
np.testing.assert_array_equal(page._origin, np.array([0, 0]))
np.testing.assert_array_equal(page._size, np.array([800, 600]))
self.assertEqual(page._background_color, (255, 255, 255))
self.assertEqual(page._mode, 'RGBA')
self.assertEqual(page._direction, 'vertical')
self.assertEqual(page._spacing, 10)
self.assertEqual(page._halign, Alignment.CENTER)
self.assertEqual(page._valign, Alignment.TOP)
def test_page_initialization_with_params(self):
"""Test page initialization with custom parameters"""
custom_size = (1024, 768)
custom_background = (240, 240, 240)
custom_mode = 'RGB'
page = Page(
size=custom_size,
background_color=custom_background,
mode=custom_mode
)
np.testing.assert_array_equal(page._size, np.array(custom_size))
self.assertEqual(page._background_color, custom_background)
self.assertEqual(page._mode, custom_mode)
def test_page_add_child(self):
"""Test adding child elements to page"""
page = Page()
page.add_child(self.mock_child1)
page.add_child(self.mock_child2)
self.assertEqual(len(page._children), 2)
self.assertEqual(page._children[0], self.mock_child1)
self.assertEqual(page._children[1], self.mock_child2)
def test_page_layout(self):
"""Test page layout functionality"""
page = Page()
page.add_child(self.mock_child1)
page.add_child(self.mock_child2)
page.layout()
# Children should be positioned vertically, centered horizontally
expected_x1 = (800 - 200) // 2 # Centered horizontally
expected_y1 = 10 # Top padding
np.testing.assert_array_equal(self.mock_child1._origin, np.array([expected_x1, expected_y1]))
expected_x2 = (800 - 150) // 2 # Centered horizontally
expected_y2 = 10 + 100 + 10 # Top padding + first child height + spacing
np.testing.assert_array_equal(self.mock_child2._origin, np.array([expected_x2, expected_y2]))
def test_page_render_empty(self):
"""Test rendering empty page"""
page = Page(size=self.page_size, background_color=self.background_color)
result = page.render()
self.assertIsInstance(result, Image.Image)
self.assertEqual(result.size, self.page_size)
self.assertEqual(result.mode, 'RGBA')
# Check that background color is applied
# Sample a pixel from the center to verify background
center_pixel = result.getpixel((400, 300))
self.assertEqual(center_pixel[:3], self.background_color)
def test_page_render_with_children_rgba(self):
"""Test rendering page with children (RGBA mode)"""
page = Page(size=self.page_size, background_color=self.background_color)
page.add_child(self.mock_child1)
page.add_child(self.mock_child2)
result = page.render()
self.assertIsInstance(result, Image.Image)
self.assertEqual(result.size, self.page_size)
self.assertEqual(result.mode, 'RGBA')
# Children should have been rendered
self.mock_child1.render.assert_called_once()
self.mock_child2.render.assert_called_once()
def test_page_render_with_children_rgb(self):
"""Test rendering page with children (RGB mode)"""
# Create children that return RGB images
rgb_child = Mock()
rgb_child._size = np.array([100, 50])
rgb_child._origin = np.array([0, 0])
rgb_child.render.return_value = Image.new('RGB', (100, 50), (255, 0, 0))
page = Page(size=self.page_size, background_color=self.background_color, mode='RGB')
page.add_child(rgb_child)
result = page.render()
self.assertIsInstance(result, Image.Image)
self.assertEqual(result.size, self.page_size)
self.assertEqual(result.mode, 'RGB')
rgb_child.render.assert_called_once()
def test_page_render_calls_layout(self):
"""Test that page render calls layout"""
page = Page()
page.add_child(self.mock_child1)
with patch.object(page, 'layout') as mock_layout:
result = page.render()
mock_layout.assert_called_once()
def test_page_inherits_container_functionality(self):
"""Test that Page inherits Container functionality"""
page = Page()
# Should inherit Container methods
self.assertTrue(hasattr(page, 'add_child'))
self.assertTrue(hasattr(page, 'layout'))
self.assertTrue(hasattr(page, '_children'))
self.assertTrue(hasattr(page, '_direction'))
self.assertTrue(hasattr(page, '_spacing'))
def test_page_with_mixed_child_image_modes(self):
"""Test page with children having different image modes"""
# Create children with different modes
rgba_child = Mock()
rgba_child._size = np.array([100, 50])
rgba_child._origin = np.array([0, 0])
rgba_child.render.return_value = Image.new('RGBA', (100, 50), (255, 0, 0, 255))
rgb_child = Mock()
rgb_child._size = np.array([100, 50])
rgb_child._origin = np.array([0, 0])
rgb_child.render.return_value = Image.new('RGB', (100, 50), (0, 255, 0))
page = Page()
page.add_child(rgba_child)
page.add_child(rgb_child)
result = page.render()
self.assertIsInstance(result, Image.Image)
self.assertEqual(result.mode, 'RGBA')
# Both children should have been rendered
rgba_child.render.assert_called_once()
rgb_child.render.assert_called_once()
def test_page_background_color_application(self):
"""Test that background color is properly applied"""
custom_bg = (100, 150, 200)
page = Page(background_color=custom_bg)
result = page.render()
# Sample multiple points to verify background
corners = [(0, 0), (799, 0), (0, 599), (799, 599)]
for corner in corners:
pixel = result.getpixel(corner)
self.assertEqual(pixel[:3], custom_bg)
def test_page_size_constraints(self):
"""Test page with various size constraints"""
small_page = Page(size=(200, 150))
large_page = Page(size=(1920, 1080))
small_result = small_page.render()
large_result = large_page.render()
self.assertEqual(small_result.size, (200, 150))
self.assertEqual(large_result.size, (1920, 1080))
class TestPageBorderMarginRendering(unittest.TestCase):
"""Test cases specifically for border/margin consistency in Page rendering"""
def setUp(self):
"""Set up test fixtures for border/margin tests"""
self.page_size = (400, 300)
self.padding = (20, 15, 25, 10) # top, right, bottom, left
self.background_color = (240, 240, 240)
def test_border_consistency_with_text_content(self):
"""Test that borders/margins are consistent when rendering text content"""
from pyWebLayout.concrete.text import Text
from pyWebLayout.style.fonts import Font
# Create page with specific padding
page = Page(size=self.page_size, background_color=self.background_color)
page._padding = self.padding
# Add text content - let Text objects calculate their own dimensions
font = Font(font_size=14)
text1 = Text("First line of text", font)
text2 = Text("Second line of text", font)
page.add_child(text1)
page.add_child(text2)
# Render the page
result = page.render()
# Extract border areas and verify consistency
border_measurements = self._extract_border_measurements(result, self.padding)
self._verify_border_consistency(border_measurements, self.padding)
# Verify content area is correctly positioned
content_area = self._extract_content_area(result, self.padding)
self.assertIsNotNone(content_area)
# Ensure content doesn't bleed into border areas
self._verify_no_content_in_borders(result, self.padding, self.background_color)
def test_border_consistency_with_paragraph_content(self):
"""Test borders/margins with paragraph content that may wrap"""
from pyWebLayout.abstract.block import Paragraph
from pyWebLayout.abstract.inline import Word
from pyWebLayout.style.fonts import Font
# Create a mock paragraph with multiple words
paragraph = Paragraph()
font = Font(font_size=12)
# Add words to create a longer paragraph
words_text = ["This", "is", "a", "longer", "paragraph", "that", "should", "wrap", "across", "multiple", "lines", "to", "test", "margin", "consistency"]
for word_text in words_text:
word = Word(word_text, font)
paragraph.add_word(word)
# Create page with specific padding
page = Page(size=self.page_size, background_color=self.background_color)
page._padding = self.padding
# Render paragraph on page
page.render_blocks([paragraph])
result = page.render()
# Extract and verify border measurements
border_measurements = self._extract_border_measurements(result, self.padding)
self._verify_border_consistency(border_measurements, self.padding)
# Verify content positioning
self._verify_content_within_bounds(result, self.padding)
def test_border_consistency_with_mixed_content(self):
"""Test borders/margins with mixed content types"""
from pyWebLayout.concrete.text import Text
from pyWebLayout.abstract.block import Paragraph, Heading, HeadingLevel
from pyWebLayout.abstract.inline import Word
from pyWebLayout.style.fonts import Font, FontWeight
# Create page with asymmetric padding to test edge cases
asymmetric_padding = (30, 20, 15, 25)
page = Page(size=(500, 400), background_color=self.background_color)
page._padding = asymmetric_padding
# Create mixed content
heading = Heading(HeadingLevel.H2)
heading_font = Font(font_size=18, weight=FontWeight.BOLD)
heading.add_word(Word("Test Heading", heading_font))
paragraph = Paragraph()
para_font = Font(font_size=12)
para_words = ["This", "paragraph", "follows", "the", "heading", "and", "tests", "mixed", "content", "rendering"]
for word_text in para_words:
paragraph.add_word(Word(word_text, para_font))
# Render mixed content
page.render_blocks([heading, paragraph])
result = page.render()
# Verify border consistency with asymmetric padding
border_measurements = self._extract_border_measurements(result, asymmetric_padding)
self._verify_border_consistency(border_measurements, asymmetric_padding)
# Verify no content bleeds into margins
self._verify_no_content_in_borders(result, asymmetric_padding, self.background_color)
def test_border_consistency_with_different_padding_values(self):
"""Test that different padding values maintain consistent borders"""
from pyWebLayout.concrete.text import Text
from pyWebLayout.style.fonts import Font
padding_configs = [
(10, 10, 10, 10), # uniform
(5, 15, 5, 15), # symmetric horizontal/vertical
(20, 30, 10, 5), # asymmetric
(0, 5, 0, 5), # minimal top/bottom
]
font = Font(font_size=14)
for padding in padding_configs:
with self.subTest(padding=padding):
# Create a fresh text object for each test to avoid state issues
test_text = Text("Border consistency test", font)
page = Page(size=self.page_size, background_color=self.background_color)
page._padding = padding
page.add_child(test_text)
result = page.render()
# Verify border measurements match expected padding
border_measurements = self._extract_border_measurements(result, padding)
self._verify_border_consistency(border_measurements, padding)
# Verify content area calculation
expected_content_width = self.page_size[0] - padding[1] - padding[3] # width - right - left
expected_content_height = self.page_size[1] - padding[0] - padding[2] # height - top - bottom
content_area = self._extract_content_area(result, padding)
self.assertEqual(content_area['width'], expected_content_width)
self.assertEqual(content_area['height'], expected_content_height)
def test_border_uniformity_across_renders(self):
"""Test that border areas remain uniform across multiple renders"""
from pyWebLayout.concrete.text import Text
from pyWebLayout.style.fonts import Font
page = Page(size=self.page_size, background_color=self.background_color)
page._padding = self.padding
font = Font(font_size=12)
text = Text("Consistency test content", font)
page.add_child(text)
# Render multiple times
results = []
for i in range(3):
result = page.render()
results.append(result)
border_measurements = self._extract_border_measurements(result, self.padding)
# Store first measurement as baseline
if i == 0:
baseline_measurements = border_measurements
else:
# Compare with baseline
self._compare_border_measurements(baseline_measurements, border_measurements)
def _extract_border_measurements(self, image, padding):
"""Extract measurements of border/margin areas from rendered image"""
width, height = image.size
top_pad, right_pad, bottom_pad, left_pad = padding
measurements = {
'top_border': {
'area': (0, 0, width, top_pad),
'pixels': self._get_area_pixels(image, (0, 0, width, top_pad))
},
'right_border': {
'area': (width - right_pad, 0, width, height),
'pixels': self._get_area_pixels(image, (width - right_pad, 0, width, height))
},
'bottom_border': {
'area': (0, height - bottom_pad, width, height),
'pixels': self._get_area_pixels(image, (0, height - bottom_pad, width, height))
},
'left_border': {
'area': (0, 0, left_pad, height),
'pixels': self._get_area_pixels(image, (0, 0, left_pad, height))
}
}
return measurements
def _get_area_pixels(self, image, area):
"""Extract pixel data from a specific area of the image"""
if area[2] <= area[0] or area[3] <= area[1]:
return [] # Invalid area
cropped = image.crop(area)
return list(cropped.getdata())
def _verify_border_consistency(self, measurements, expected_padding):
"""Verify that border measurements match expected padding values"""
# Get actual dimensions from the measurements instead of using self.page_size
# This allows the test to work with different page sizes
top_area = measurements['top_border']['area']
width = top_area[2] # right coordinate of top border gives us the width
height = measurements['left_border']['area'][3] # bottom coordinate of left border gives us the height
top_pad, right_pad, bottom_pad, left_pad = expected_padding
# Check area dimensions
self.assertEqual(top_area, (0, 0, width, top_pad))
right_area = measurements['right_border']['area']
self.assertEqual(right_area, (width - right_pad, 0, width, height))
bottom_area = measurements['bottom_border']['area']
self.assertEqual(bottom_area, (0, height - bottom_pad, width, height))
left_area = measurements['left_border']['area']
self.assertEqual(left_area, (0, 0, left_pad, height))
def _extract_content_area(self, image, padding):
"""Extract the content area (area inside borders/margins)"""
width, height = image.size
top_pad, right_pad, bottom_pad, left_pad = padding
content_area = {
'left': left_pad,
'top': top_pad,
'right': width - right_pad,
'bottom': height - bottom_pad,
'width': width - left_pad - right_pad,
'height': height - top_pad - bottom_pad
}
return content_area
def _verify_no_content_in_borders(self, image, padding, background_color):
"""Verify that no content bleeds into the border/margin areas"""
measurements = self._extract_border_measurements(image, padding)
# Check that border areas contain only background color
for border_name, border_data in measurements.items():
pixels = border_data['pixels']
if pixels: # Only check if area is not empty
# Most pixels should be background color (allowing for some anti-aliasing)
bg_count = sum(1 for pixel in pixels if self._is_background_color(pixel, background_color))
total_pixels = len(pixels)
# Allow up to 10% deviation for anti-aliasing effects
bg_ratio = bg_count / total_pixels if total_pixels > 0 else 1.0
self.assertGreaterEqual(bg_ratio, 0.9,
f"Border area '{border_name}' contains too much non-background content. "
f"Background ratio: {bg_ratio:.2f}")
def _is_background_color(self, pixel, background_color, tolerance=10):
"""Check if a pixel is close to the background color within tolerance"""
if len(pixel) >= 3:
r_diff = abs(pixel[0] - background_color[0])
g_diff = abs(pixel[1] - background_color[1])
b_diff = abs(pixel[2] - background_color[2])
return r_diff <= tolerance and g_diff <= tolerance and b_diff <= tolerance
return False
def _verify_content_within_bounds(self, image, padding):
"""Verify that content is positioned within the expected bounds"""
content_area = self._extract_content_area(image, padding)
# Sample the content area to ensure it's not all background
if content_area['width'] > 0 and content_area['height'] > 0:
content_crop = image.crop((
content_area['left'],
content_area['top'],
content_area['right'],
content_area['bottom']
))
# Content area should have some non-background pixels
content_pixels = list(content_crop.getdata())
non_bg_pixels = sum(1 for pixel in content_pixels
if not self._is_background_color(pixel, self.background_color))
# Expect at least some content in the content area
self.assertGreater(non_bg_pixels, 0, "Content area appears to be empty")
def _compare_border_measurements(self, baseline, current):
"""Compare two sets of border measurements for consistency"""
for border_name in baseline.keys():
baseline_area = baseline[border_name]['area']
current_area = current[border_name]['area']
self.assertEqual(baseline_area, current_area,
f"Border area '{border_name}' is inconsistent between renders")
if __name__ == '__main__':
unittest.main()