""" Unit tests for pyWebLayout.concrete.box module. Tests the Box class which handles basic box model rendering with alignment. """ import unittest import numpy as np from PIL import Image from unittest.mock import Mock, patch from pyWebLayout.concrete.box import Box from pyWebLayout.style.layout import Alignment class TestBox(unittest.TestCase): """Test cases for the Box class""" def setUp(self): """Set up test fixtures""" self.origin = (10, 20) self.size = (100, 50) self.callback = Mock() def test_box_initialization_basic(self): """Test basic box initialization""" box = Box(self.origin, self.size) np.testing.assert_array_equal(box._origin, np.array([10, 20])) np.testing.assert_array_equal(box._size, np.array([100, 50])) np.testing.assert_array_equal(box._end, np.array([110, 70])) self.assertIsNone(box._callback) self.assertIsNone(box._sheet) self.assertIsNone(box._mode) self.assertEqual(box._halign, Alignment.CENTER) self.assertEqual(box._valign, Alignment.CENTER) def test_box_initialization_with_callback(self): """Test box initialization with callback""" box = Box(self.origin, self.size, callback=self.callback) self.assertEqual(box._callback, self.callback) def test_box_initialization_with_sheet(self): """Test box initialization with image sheet""" sheet = Image.new('RGBA', (200, 100), (255, 255, 255, 255)) box = Box(self.origin, self.size, sheet=sheet) self.assertEqual(box._sheet, sheet) self.assertEqual(box._mode, 'RGBA') def test_box_initialization_with_mode(self): """Test box initialization with explicit mode""" box = Box(self.origin, self.size, mode='RGB') self.assertEqual(box._mode, 'RGB') def test_box_initialization_with_alignment(self): """Test box initialization with custom alignment""" box = Box(self.origin, self.size, halign=Alignment.LEFT, valign=Alignment.TOP) self.assertEqual(box._halign, Alignment.LEFT) self.assertEqual(box._valign, Alignment.TOP) def test_in_shape_point_inside(self): """Test in_shape method with point inside box""" box = Box(self.origin, self.size) # Test point inside self.assertTrue(box.in_shape(np.array([50, 40]))) self.assertTrue(box.in_shape(np.array([10, 20]))) # Top-left corner self.assertTrue(box.in_shape(np.array([109, 69]))) # Just inside bottom-right def test_in_shape_point_outside(self): """Test in_shape method with point outside box""" box = Box(self.origin, self.size) # Test points outside self.assertFalse(box.in_shape(np.array([5, 15]))) # Before origin self.assertFalse(box.in_shape(np.array([110, 70]))) # At end (exclusive) self.assertFalse(box.in_shape(np.array([150, 100]))) # Far outside def test_in_shape_multiple_points(self): """Test in_shape method with array of points""" box = Box(self.origin, self.size) points = np.array([[50, 40], [5, 15], [109, 69], [110, 70]]) result = box.in_shape(points) np.testing.assert_array_equal(result, [True, False, True, False]) def test_render_default_no_content(self): """Test render method with no content""" box = Box(self.origin, self.size) result = box.render() self.assertIsInstance(result, Image.Image) self.assertEqual(result.size, tuple(self.size)) self.assertEqual(result.mode, 'RGBA') def test_render_with_sheet_mode(self): """Test render method with sheet providing mode""" sheet = Image.new('RGB', (200, 100), (255, 0, 0)) box = Box(self.origin, self.size, sheet=sheet) result = box.render() self.assertIsInstance(result, Image.Image) self.assertEqual(result.size, tuple(self.size)) self.assertEqual(result.mode, 'RGB') def test_render_with_explicit_mode(self): """Test render method with explicit mode""" box = Box(self.origin, self.size, mode='L') # Grayscale result = box.render() self.assertIsInstance(result, Image.Image) self.assertEqual(result.size, tuple(self.size)) self.assertEqual(result.mode, 'L') def test_render_with_content_centered(self): """Test render method with content centered""" box = Box(self.origin, self.size, halign=Alignment.CENTER, valign=Alignment.CENTER) # Mock content that has a render method mock_content = Mock() mock_content.render.return_value = Image.new('RGBA', (50, 30), (255, 0, 0, 255)) box._content = mock_content result = box.render() self.assertIsInstance(result, Image.Image) self.assertEqual(result.size, tuple(self.size)) mock_content.render.assert_called_once() def test_render_with_content_left_aligned(self): """Test render method with content left-aligned""" box = Box(self.origin, self.size, halign=Alignment.LEFT, valign=Alignment.TOP) # Mock content mock_content = Mock() mock_content.render.return_value = Image.new('RGBA', (30, 20), (0, 255, 0, 255)) box._content = mock_content result = box.render() self.assertIsInstance(result, Image.Image) self.assertEqual(result.size, tuple(self.size)) mock_content.render.assert_called_once() def test_render_with_content_right_aligned(self): """Test render method with content right-aligned""" box = Box(self.origin, self.size, halign=Alignment.RIGHT, valign=Alignment.BOTTOM) # Mock content mock_content = Mock() mock_content.render.return_value = Image.new('RGBA', (40, 25), (0, 0, 255, 255)) box._content = mock_content result = box.render() self.assertIsInstance(result, Image.Image) self.assertEqual(result.size, tuple(self.size)) mock_content.render.assert_called_once() def test_render_content_larger_than_box(self): """Test render method when content is larger than box""" small_box = Box((0, 0), (20, 15)) # Mock content larger than box mock_content = Mock() mock_content.render.return_value = Image.new('RGBA', (50, 40), (255, 255, 0, 255)) small_box._content = mock_content result = small_box.render() # Should still create box-sized canvas self.assertEqual(result.size, (20, 15)) mock_content.render.assert_called_once() def test_properties_access(self): """Test that properties can be accessed correctly""" box = Box(self.origin, self.size, callback=self.callback) # Test that origin property works (should be available via inheritance) np.testing.assert_array_equal(box._origin, np.array([10, 20])) np.testing.assert_array_equal(box._size, np.array([100, 50])) if __name__ == '__main__': unittest.main()