auto flake and corrections
This commit is contained in:
@@ -12,9 +12,9 @@ import threading
|
||||
import time
|
||||
from PIL import Image as PILImage
|
||||
from pyWebLayout.abstract.block import (
|
||||
Block, BlockType, Paragraph, Heading, HeadingLevel, Quote, CodeBlock,
|
||||
HList, ListStyle, ListItem, Table, TableRow, TableCell,
|
||||
HorizontalRule, Image
|
||||
BlockType, Paragraph, Heading, HeadingLevel, Quote, CodeBlock, HList,
|
||||
ListStyle, ListItem, Table, TableRow, TableCell, HorizontalRule,
|
||||
Image
|
||||
)
|
||||
from pyWebLayout.abstract.inline import Word, LineBreak
|
||||
from pyWebLayout.style import Font
|
||||
@@ -29,256 +29,256 @@ except ImportError:
|
||||
|
||||
class TestBlockElements(unittest.TestCase):
|
||||
"""Test cases for basic block elements."""
|
||||
|
||||
|
||||
def test_paragraph_creation(self):
|
||||
"""Test creating and using paragraphs."""
|
||||
paragraph = Paragraph()
|
||||
|
||||
|
||||
self.assertEqual(paragraph.block_type, BlockType.PARAGRAPH)
|
||||
self.assertEqual(paragraph.word_count, 0)
|
||||
self.assertIsNone(paragraph.parent)
|
||||
|
||||
|
||||
# Add words
|
||||
font = Font()
|
||||
word1 = Word("Hello", font)
|
||||
word2 = Word("World", font)
|
||||
|
||||
|
||||
paragraph.add_word(word1)
|
||||
paragraph.add_word(word2)
|
||||
|
||||
|
||||
self.assertEqual(paragraph.word_count, 2)
|
||||
|
||||
|
||||
# Test word iteration
|
||||
words = list(paragraph.words_iter())
|
||||
self.assertEqual(len(words), 2)
|
||||
self.assertEqual(words[0][1].text, "Hello")
|
||||
self.assertEqual(words[1][1].text, "World")
|
||||
|
||||
|
||||
def test_heading_levels(self):
|
||||
"""Test heading creation with different levels."""
|
||||
h1 = Heading(HeadingLevel.H1)
|
||||
h3 = Heading(HeadingLevel.H3)
|
||||
h6 = Heading(HeadingLevel.H6)
|
||||
|
||||
|
||||
self.assertEqual(h1.level, HeadingLevel.H1)
|
||||
self.assertEqual(h3.level, HeadingLevel.H3)
|
||||
self.assertEqual(h6.level, HeadingLevel.H6)
|
||||
|
||||
|
||||
self.assertEqual(h1.block_type, BlockType.HEADING)
|
||||
|
||||
|
||||
# Test level modification
|
||||
h1.level = HeadingLevel.H2
|
||||
self.assertEqual(h1.level, HeadingLevel.H2)
|
||||
|
||||
|
||||
def test_quote_nesting(self):
|
||||
"""Test blockquote with nested content."""
|
||||
quote = Quote()
|
||||
|
||||
|
||||
# Add nested paragraphs
|
||||
p1 = Paragraph()
|
||||
p2 = Paragraph()
|
||||
|
||||
|
||||
quote.add_block(p1)
|
||||
quote.add_block(p2)
|
||||
|
||||
|
||||
self.assertEqual(p1.parent, quote)
|
||||
self.assertEqual(p2.parent, quote)
|
||||
|
||||
|
||||
# Test block iteration
|
||||
blocks = list(quote.blocks())
|
||||
self.assertEqual(len(blocks), 2)
|
||||
self.assertEqual(blocks[0], p1)
|
||||
self.assertEqual(blocks[1], p2)
|
||||
|
||||
|
||||
def test_code_block(self):
|
||||
"""Test code block functionality."""
|
||||
code = CodeBlock("python")
|
||||
|
||||
|
||||
self.assertEqual(code.language, "python")
|
||||
self.assertEqual(code.line_count, 0)
|
||||
|
||||
|
||||
# Add code lines
|
||||
code.add_line("def hello():")
|
||||
code.add_line(" print('Hello!')")
|
||||
|
||||
|
||||
self.assertEqual(code.line_count, 2)
|
||||
|
||||
|
||||
# Test line iteration
|
||||
lines = list(code.lines())
|
||||
self.assertEqual(len(lines), 2)
|
||||
self.assertEqual(lines[0][1], "def hello():")
|
||||
self.assertEqual(lines[1][1], " print('Hello!')")
|
||||
|
||||
|
||||
# Test language modification
|
||||
code.language = "javascript"
|
||||
self.assertEqual(code.language, "javascript")
|
||||
|
||||
|
||||
def test_list_creation(self):
|
||||
"""Test list creation and item management."""
|
||||
# Unordered list
|
||||
ul = HList(ListStyle.UNORDERED)
|
||||
self.assertEqual(ul.style, ListStyle.UNORDERED)
|
||||
self.assertEqual(ul.item_count, 0)
|
||||
|
||||
|
||||
# Add list items
|
||||
item1 = ListItem()
|
||||
item2 = ListItem()
|
||||
|
||||
|
||||
ul.add_item(item1)
|
||||
ul.add_item(item2)
|
||||
|
||||
|
||||
self.assertEqual(ul.item_count, 2)
|
||||
self.assertEqual(item1.parent, ul)
|
||||
self.assertEqual(item2.parent, ul)
|
||||
|
||||
|
||||
# Test item iteration
|
||||
items = list(ul.items())
|
||||
self.assertEqual(len(items), 2)
|
||||
|
||||
|
||||
# Test list style change
|
||||
ul.style = ListStyle.ORDERED
|
||||
self.assertEqual(ul.style, ListStyle.ORDERED)
|
||||
|
||||
|
||||
def test_definition_list(self):
|
||||
"""Test definition list with terms."""
|
||||
dl = HList(ListStyle.DEFINITION)
|
||||
|
||||
|
||||
# Add definition items with terms
|
||||
dt1 = ListItem(term="Python")
|
||||
dt2 = ListItem(term="JavaScript")
|
||||
|
||||
|
||||
dl.add_item(dt1)
|
||||
dl.add_item(dt2)
|
||||
|
||||
|
||||
self.assertEqual(dt1.term, "Python")
|
||||
self.assertEqual(dt2.term, "JavaScript")
|
||||
|
||||
|
||||
# Test term modification
|
||||
dt1.term = "Python 3"
|
||||
self.assertEqual(dt1.term, "Python 3")
|
||||
|
||||
|
||||
def test_table_structure(self):
|
||||
"""Test table, row, and cell structure."""
|
||||
table = Table(caption="Test Table")
|
||||
|
||||
|
||||
self.assertEqual(table.caption, "Test Table")
|
||||
self.assertEqual(table.row_count["total"], 0)
|
||||
|
||||
|
||||
# Create rows and cells
|
||||
header_row = TableRow()
|
||||
data_row = TableRow()
|
||||
|
||||
|
||||
# Header cells
|
||||
h1 = TableCell(is_header=True)
|
||||
h2 = TableCell(is_header=True)
|
||||
header_row.add_cell(h1)
|
||||
header_row.add_cell(h2)
|
||||
|
||||
|
||||
# Data cells
|
||||
d1 = TableCell(is_header=False)
|
||||
d2 = TableCell(is_header=False, colspan=2)
|
||||
data_row.add_cell(d1)
|
||||
data_row.add_cell(d2)
|
||||
|
||||
|
||||
# Add rows to table
|
||||
table.add_row(header_row, "header")
|
||||
table.add_row(data_row, "body")
|
||||
|
||||
|
||||
# Test structure
|
||||
self.assertEqual(table.row_count["header"], 1)
|
||||
self.assertEqual(table.row_count["body"], 1)
|
||||
self.assertEqual(table.row_count["total"], 2)
|
||||
|
||||
|
||||
# Test cell properties
|
||||
self.assertTrue(h1.is_header)
|
||||
self.assertFalse(d1.is_header)
|
||||
self.assertEqual(d2.colspan, 2)
|
||||
self.assertEqual(d2.rowspan, 1) # Default
|
||||
|
||||
|
||||
# Test row cell count
|
||||
self.assertEqual(header_row.cell_count, 2)
|
||||
self.assertEqual(data_row.cell_count, 2)
|
||||
|
||||
|
||||
def test_table_sections(self):
|
||||
"""Test table header, body, and footer sections."""
|
||||
table = Table()
|
||||
|
||||
|
||||
# Add rows to different sections
|
||||
header = TableRow()
|
||||
body1 = TableRow()
|
||||
body2 = TableRow()
|
||||
footer = TableRow()
|
||||
|
||||
|
||||
table.add_row(header, "header")
|
||||
table.add_row(body1, "body")
|
||||
table.add_row(body2, "body")
|
||||
table.add_row(footer, "footer")
|
||||
|
||||
|
||||
# Test section iteration
|
||||
header_rows = list(table.header_rows())
|
||||
body_rows = list(table.body_rows())
|
||||
footer_rows = list(table.footer_rows())
|
||||
|
||||
|
||||
self.assertEqual(len(header_rows), 1)
|
||||
self.assertEqual(len(body_rows), 2)
|
||||
self.assertEqual(len(footer_rows), 1)
|
||||
|
||||
|
||||
# Test all_rows iteration
|
||||
all_rows = list(table.all_rows())
|
||||
self.assertEqual(len(all_rows), 4)
|
||||
|
||||
|
||||
# Check section labels
|
||||
sections = [section for section, row in all_rows]
|
||||
self.assertEqual(sections, ["header", "body", "body", "footer"])
|
||||
|
||||
|
||||
def test_image_loading(self):
|
||||
"""Test image element properties."""
|
||||
# Test with basic properties
|
||||
img = Image("test.jpg", "Test image", 100, 200)
|
||||
|
||||
|
||||
self.assertEqual(img.source, "test.jpg")
|
||||
self.assertEqual(img.alt_text, "Test image")
|
||||
self.assertEqual(img.width, 100)
|
||||
self.assertEqual(img.height, 200)
|
||||
|
||||
|
||||
# Test property modification
|
||||
img.source = "new.png"
|
||||
img.alt_text = "New image"
|
||||
img.width = 150
|
||||
img.height = 300
|
||||
|
||||
|
||||
self.assertEqual(img.source, "new.png")
|
||||
self.assertEqual(img.alt_text, "New image")
|
||||
self.assertEqual(img.width, 150)
|
||||
self.assertEqual(img.height, 300)
|
||||
|
||||
|
||||
# Test dimensions tuple
|
||||
self.assertEqual(img.get_dimensions(), (150, 300))
|
||||
|
||||
|
||||
def test_aspect_ratio_calculation(self):
|
||||
"""Test image aspect ratio calculations."""
|
||||
# Test with specified dimensions
|
||||
img = Image("test.jpg", width=400, height=200)
|
||||
self.assertEqual(img.get_aspect_ratio(), 2.0) # 400/200
|
||||
|
||||
|
||||
# Test with only one dimension
|
||||
img2 = Image("test.jpg", width=300)
|
||||
self.assertIsNone(img2.get_aspect_ratio()) # No height specified
|
||||
|
||||
|
||||
# Test scaled dimensions
|
||||
scaled = img.calculate_scaled_dimensions(max_width=200, max_height=150)
|
||||
# Should scale down proportionally
|
||||
self.assertEqual(scaled[0], 200) # Width limited by max_width
|
||||
self.assertEqual(scaled[1], 100) # Height scaled proportionally
|
||||
|
||||
|
||||
def test_simple_elements(self):
|
||||
"""Test simple block elements."""
|
||||
hr = HorizontalRule()
|
||||
br = LineBreak()
|
||||
|
||||
|
||||
self.assertEqual(hr.block_type, BlockType.HORIZONTAL_RULE)
|
||||
self.assertEqual(br.block_type, BlockType.LINE_BREAK)
|
||||
|
||||
|
||||
# These elements have no additional properties
|
||||
self.assertIsNone(hr.parent)
|
||||
self.assertIsNone(br.parent)
|
||||
@@ -286,29 +286,29 @@ class TestBlockElements(unittest.TestCase):
|
||||
|
||||
class TestImagePIL(unittest.TestCase):
|
||||
"""Test cases for Image class with PIL functionality."""
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""Set up temporary directory and test images."""
|
||||
cls.temp_dir = tempfile.mkdtemp()
|
||||
cls.sample_image_path = "tests/data/sample_image.jpg"
|
||||
|
||||
|
||||
# Create test images in different formats
|
||||
cls._create_test_images()
|
||||
|
||||
|
||||
# Start Flask server for URL testing if Flask is available
|
||||
if FLASK_AVAILABLE:
|
||||
cls._start_flask_server()
|
||||
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
"""Clean up temporary directory and stop Flask server."""
|
||||
shutil.rmtree(cls.temp_dir, ignore_errors=True)
|
||||
|
||||
|
||||
if FLASK_AVAILABLE and hasattr(cls, 'flask_thread'):
|
||||
cls.flask_server_running = False
|
||||
cls.flask_thread.join(timeout=2)
|
||||
|
||||
|
||||
@classmethod
|
||||
def _create_test_images(cls):
|
||||
"""Create test images in different formats."""
|
||||
@@ -316,17 +316,17 @@ class TestImagePIL(unittest.TestCase):
|
||||
if os.path.exists(cls.sample_image_path):
|
||||
with PILImage.open(cls.sample_image_path) as img:
|
||||
cls.original_size = img.size
|
||||
|
||||
|
||||
# Save in different formats
|
||||
cls.jpg_path = os.path.join(cls.temp_dir, "test.jpg")
|
||||
cls.png_path = os.path.join(cls.temp_dir, "test.png")
|
||||
cls.bmp_path = os.path.join(cls.temp_dir, "test.bmp")
|
||||
cls.gif_path = os.path.join(cls.temp_dir, "test.gif")
|
||||
|
||||
|
||||
img.save(cls.jpg_path, "JPEG")
|
||||
img.save(cls.png_path, "PNG")
|
||||
img.save(cls.bmp_path, "BMP")
|
||||
|
||||
|
||||
# Convert to RGB for GIF (GIF doesn't support transparency from RGBA)
|
||||
rgb_img = img.convert("RGB")
|
||||
rgb_img.save(cls.gif_path, "GIF")
|
||||
@@ -334,17 +334,17 @@ class TestImagePIL(unittest.TestCase):
|
||||
# Create a simple test image if sample doesn't exist
|
||||
cls.original_size = (100, 100)
|
||||
test_img = PILImage.new("RGB", cls.original_size, (255, 0, 0))
|
||||
|
||||
|
||||
cls.jpg_path = os.path.join(cls.temp_dir, "test.jpg")
|
||||
cls.png_path = os.path.join(cls.temp_dir, "test.png")
|
||||
cls.bmp_path = os.path.join(cls.temp_dir, "test.bmp")
|
||||
cls.gif_path = os.path.join(cls.temp_dir, "test.gif")
|
||||
|
||||
|
||||
test_img.save(cls.jpg_path, "JPEG")
|
||||
test_img.save(cls.png_path, "PNG")
|
||||
test_img.save(cls.bmp_path, "BMP")
|
||||
test_img.save(cls.gif_path, "GIF")
|
||||
|
||||
|
||||
@classmethod
|
||||
def _start_flask_server(cls):
|
||||
"""Start a Flask server for URL testing."""
|
||||
@@ -365,7 +365,7 @@ class TestImagePIL(unittest.TestCase):
|
||||
|
||||
def run_flask():
|
||||
cls.flask_app.run(host='127.0.0.1', port=cls.flask_port, debug=False,
|
||||
use_reloader=False, threaded=True)
|
||||
use_reloader=False, threaded=True)
|
||||
|
||||
cls.flask_thread = threading.Thread(target=run_flask, daemon=True)
|
||||
cls.flask_thread.start()
|
||||
@@ -384,120 +384,120 @@ class TestImagePIL(unittest.TestCase):
|
||||
pass
|
||||
time.sleep(wait_interval)
|
||||
elapsed += wait_interval
|
||||
|
||||
|
||||
def test_image_url_detection(self):
|
||||
"""Test URL detection functionality."""
|
||||
img = Image()
|
||||
|
||||
|
||||
# Test URL detection
|
||||
self.assertTrue(img._is_url("http://example.com/image.jpg"))
|
||||
self.assertTrue(img._is_url("https://example.com/image.png"))
|
||||
self.assertTrue(img._is_url("ftp://example.com/image.gif"))
|
||||
|
||||
|
||||
# Test non-URL detection
|
||||
self.assertFalse(img._is_url("image.jpg"))
|
||||
self.assertFalse(img._is_url("/path/to/image.png"))
|
||||
self.assertFalse(img._is_url("../relative/path.gif"))
|
||||
self.assertFalse(img._is_url(""))
|
||||
|
||||
|
||||
def test_load_local_image_jpg(self):
|
||||
"""Test loading local JPG image."""
|
||||
img = Image(self.jpg_path)
|
||||
|
||||
|
||||
file_path, pil_img = img.load_image_data()
|
||||
|
||||
|
||||
self.assertIsNotNone(pil_img)
|
||||
self.assertEqual(file_path, self.jpg_path)
|
||||
self.assertEqual(pil_img.size, self.original_size)
|
||||
self.assertEqual(img.width, self.original_size[0])
|
||||
self.assertEqual(img.height, self.original_size[1])
|
||||
|
||||
|
||||
def test_load_local_image_png(self):
|
||||
"""Test loading local PNG image."""
|
||||
img = Image(self.png_path)
|
||||
|
||||
|
||||
file_path, pil_img = img.load_image_data()
|
||||
|
||||
|
||||
self.assertIsNotNone(pil_img)
|
||||
self.assertEqual(file_path, self.png_path)
|
||||
self.assertEqual(pil_img.size, self.original_size)
|
||||
|
||||
|
||||
def test_load_local_image_bmp(self):
|
||||
"""Test loading local BMP image."""
|
||||
img = Image(self.bmp_path)
|
||||
|
||||
|
||||
file_path, pil_img = img.load_image_data()
|
||||
|
||||
|
||||
self.assertIsNotNone(pil_img)
|
||||
self.assertEqual(file_path, self.bmp_path)
|
||||
self.assertEqual(pil_img.size, self.original_size)
|
||||
|
||||
|
||||
def test_load_local_image_gif(self):
|
||||
"""Test loading local GIF image."""
|
||||
img = Image(self.gif_path)
|
||||
|
||||
|
||||
file_path, pil_img = img.load_image_data()
|
||||
|
||||
|
||||
self.assertIsNotNone(pil_img)
|
||||
self.assertEqual(file_path, self.gif_path)
|
||||
self.assertEqual(pil_img.size, self.original_size)
|
||||
|
||||
|
||||
def test_load_nonexistent_image(self):
|
||||
"""Test loading non-existent image."""
|
||||
img = Image("nonexistent.jpg")
|
||||
|
||||
|
||||
file_path, pil_img = img.load_image_data()
|
||||
|
||||
|
||||
self.assertIsNone(pil_img)
|
||||
self.assertIsNone(file_path)
|
||||
|
||||
|
||||
def test_load_empty_source(self):
|
||||
"""Test loading with empty source."""
|
||||
img = Image("")
|
||||
|
||||
|
||||
file_path, pil_img = img.load_image_data()
|
||||
|
||||
|
||||
self.assertIsNone(pil_img)
|
||||
self.assertIsNone(file_path)
|
||||
|
||||
|
||||
def test_auto_update_dimensions(self):
|
||||
"""Test automatic dimension updating."""
|
||||
img = Image(self.jpg_path, width=50, height=50) # Wrong initial dimensions
|
||||
|
||||
|
||||
# Test with auto-update enabled (default)
|
||||
file_path, pil_img = img.load_image_data(auto_update_dimensions=True)
|
||||
|
||||
|
||||
self.assertEqual(img.width, self.original_size[0])
|
||||
self.assertEqual(img.height, self.original_size[1])
|
||||
|
||||
|
||||
def test_no_auto_update_dimensions(self):
|
||||
"""Test loading without automatic dimension updating."""
|
||||
original_width, original_height = 50, 50
|
||||
img = Image(self.jpg_path, width=original_width, height=original_height)
|
||||
|
||||
|
||||
# Test with auto-update disabled
|
||||
file_path, pil_img = img.load_image_data(auto_update_dimensions=False)
|
||||
|
||||
|
||||
self.assertEqual(img.width, original_width) # Should remain unchanged
|
||||
self.assertEqual(img.height, original_height) # Should remain unchanged
|
||||
|
||||
|
||||
def test_get_image_info(self):
|
||||
"""Test getting detailed image information."""
|
||||
img = Image(self.jpg_path)
|
||||
|
||||
|
||||
info = img.get_image_info()
|
||||
|
||||
|
||||
self.assertIsInstance(info, dict)
|
||||
self.assertIn('format', info)
|
||||
self.assertIn('mode', info)
|
||||
self.assertIn('size', info)
|
||||
self.assertIn('width', info)
|
||||
self.assertIn('height', info)
|
||||
|
||||
|
||||
self.assertEqual(info['size'], self.original_size)
|
||||
self.assertEqual(info['width'], self.original_size[0])
|
||||
self.assertEqual(info['height'], self.original_size[1])
|
||||
|
||||
|
||||
def test_get_image_info_different_formats(self):
|
||||
"""Test getting image info for different formats."""
|
||||
formats_and_paths = [
|
||||
@@ -506,80 +506,80 @@ class TestImagePIL(unittest.TestCase):
|
||||
('BMP', self.bmp_path),
|
||||
('GIF', self.gif_path),
|
||||
]
|
||||
|
||||
|
||||
for expected_format, path in formats_and_paths:
|
||||
with self.subTest(format=expected_format):
|
||||
img = Image(path)
|
||||
info = img.get_image_info()
|
||||
|
||||
|
||||
self.assertEqual(info['format'], expected_format)
|
||||
self.assertEqual(info['size'], self.original_size)
|
||||
|
||||
|
||||
def test_get_image_info_nonexistent(self):
|
||||
"""Test getting image info for non-existent image."""
|
||||
img = Image("nonexistent.jpg")
|
||||
|
||||
|
||||
info = img.get_image_info()
|
||||
|
||||
|
||||
self.assertEqual(info, {})
|
||||
|
||||
|
||||
@unittest.skipUnless(FLASK_AVAILABLE, "Flask not available for URL testing")
|
||||
def test_load_image_from_url(self):
|
||||
"""Test loading image from URL."""
|
||||
url = f"http://127.0.0.1:{self.flask_port}/test.jpg"
|
||||
img = Image(url)
|
||||
|
||||
|
||||
file_path, pil_img = img.load_image_data()
|
||||
|
||||
|
||||
self.assertIsNotNone(pil_img)
|
||||
self.assertIsNotNone(file_path)
|
||||
self.assertTrue(file_path.endswith('.tmp')) # Should be a temp file
|
||||
self.assertEqual(pil_img.size, self.original_size)
|
||||
|
||||
|
||||
# Check that dimensions were updated
|
||||
self.assertEqual(img.width, self.original_size[0])
|
||||
self.assertEqual(img.height, self.original_size[1])
|
||||
|
||||
|
||||
@unittest.skipUnless(FLASK_AVAILABLE, "Flask not available for URL testing")
|
||||
def test_get_image_info_from_url(self):
|
||||
"""Test getting image info from URL."""
|
||||
url = f"http://127.0.0.1:{self.flask_port}/test.jpg"
|
||||
img = Image(url)
|
||||
|
||||
|
||||
info = img.get_image_info()
|
||||
|
||||
|
||||
self.assertIsInstance(info, dict)
|
||||
self.assertEqual(info['format'], 'JPEG')
|
||||
self.assertEqual(info['size'], self.original_size)
|
||||
|
||||
|
||||
def test_load_invalid_url(self):
|
||||
"""Test loading from invalid URL."""
|
||||
img = Image("http://nonexistent.domain/image.jpg")
|
||||
|
||||
|
||||
file_path, pil_img = img.load_image_data()
|
||||
|
||||
|
||||
self.assertIsNone(pil_img)
|
||||
self.assertIsNone(file_path)
|
||||
|
||||
|
||||
def test_multiple_loads_cleanup(self):
|
||||
"""Test that multiple loads don't leave temp files."""
|
||||
img = Image(self.jpg_path)
|
||||
|
||||
|
||||
# Load multiple times
|
||||
for _ in range(3):
|
||||
file_path, pil_img = img.load_image_data()
|
||||
self.assertIsNotNone(pil_img)
|
||||
|
||||
|
||||
def test_original_sample_image(self):
|
||||
"""Test loading the original sample image if it exists."""
|
||||
if os.path.exists(self.sample_image_path):
|
||||
img = Image(self.sample_image_path)
|
||||
|
||||
|
||||
file_path, pil_img = img.load_image_data()
|
||||
|
||||
|
||||
self.assertIsNotNone(pil_img)
|
||||
self.assertEqual(file_path, self.sample_image_path)
|
||||
|
||||
|
||||
# Test that we can get image info
|
||||
info = img.get_image_info()
|
||||
self.assertIsInstance(info, dict)
|
||||
|
||||
@@ -8,13 +8,13 @@ document structure and metadata management.
|
||||
import unittest
|
||||
from pyWebLayout.abstract.document import Document, Chapter, Book, MetadataType
|
||||
from pyWebLayout.abstract.block import Paragraph, Heading, HeadingLevel, BlockType
|
||||
from pyWebLayout.abstract.inline import Word, FormattedSpan
|
||||
from pyWebLayout.abstract.inline import Word
|
||||
from pyWebLayout.style import Font, FontWeight, FontStyle, TextDecoration
|
||||
|
||||
|
||||
class TestMetadataType(unittest.TestCase):
|
||||
"""Test cases for MetadataType enum."""
|
||||
|
||||
|
||||
def test_metadata_types(self):
|
||||
"""Test that all expected metadata types exist."""
|
||||
expected_types = [
|
||||
@@ -22,135 +22,141 @@ class TestMetadataType(unittest.TestCase):
|
||||
'PUBLICATION_DATE', 'MODIFIED_DATE', 'PUBLISHER', 'IDENTIFIER',
|
||||
'COVER_IMAGE', 'CUSTOM'
|
||||
]
|
||||
|
||||
|
||||
for type_name in expected_types:
|
||||
self.assertTrue(hasattr(MetadataType, type_name))
|
||||
|
||||
|
||||
# Test custom type has expected value
|
||||
self.assertEqual(MetadataType.CUSTOM.value, 100)
|
||||
|
||||
|
||||
class TestDocument(unittest.TestCase):
|
||||
"""Test cases for Document class."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.doc = Document("Test Document", "en-US")
|
||||
self.font = Font()
|
||||
|
||||
|
||||
def test_document_creation(self):
|
||||
"""Test document creation with basic parameters."""
|
||||
self.assertEqual(self.doc.get_title(), "Test Document")
|
||||
self.assertEqual(self.doc.get_metadata(MetadataType.LANGUAGE), "en-US")
|
||||
self.assertEqual(len(self.doc.blocks), 0)
|
||||
|
||||
|
||||
def test_document_creation_minimal(self):
|
||||
"""Test document creation with minimal parameters."""
|
||||
doc = Document()
|
||||
self.assertIsNone(doc.get_title())
|
||||
self.assertEqual(doc.get_metadata(MetadataType.LANGUAGE), "en-US")
|
||||
|
||||
|
||||
def test_metadata_management(self):
|
||||
"""Test setting and getting metadata."""
|
||||
# Set various metadata types
|
||||
self.doc.set_metadata(MetadataType.AUTHOR, "John Doe")
|
||||
self.doc.set_metadata(MetadataType.DESCRIPTION, "A test document")
|
||||
self.doc.set_metadata(MetadataType.KEYWORDS, ["test", "document"])
|
||||
|
||||
|
||||
# Test retrieval
|
||||
self.assertEqual(self.doc.get_metadata(MetadataType.AUTHOR), "John Doe")
|
||||
self.assertEqual(self.doc.get_metadata(MetadataType.DESCRIPTION), "A test document")
|
||||
self.assertEqual(self.doc.get_metadata(MetadataType.KEYWORDS), ["test", "document"])
|
||||
|
||||
self.assertEqual(
|
||||
self.doc.get_metadata(
|
||||
MetadataType.DESCRIPTION),
|
||||
"A test document")
|
||||
self.assertEqual(
|
||||
self.doc.get_metadata(
|
||||
MetadataType.KEYWORDS), [
|
||||
"test", "document"])
|
||||
|
||||
# Test non-existent metadata
|
||||
self.assertIsNone(self.doc.get_metadata(MetadataType.PUBLISHER))
|
||||
|
||||
|
||||
def test_title_convenience_methods(self):
|
||||
"""Test title getter and setter convenience methods."""
|
||||
# Test setting title
|
||||
self.doc.set_title("New Title")
|
||||
self.assertEqual(self.doc.get_title(), "New Title")
|
||||
|
||||
|
||||
# Test that it's also in metadata
|
||||
self.assertEqual(self.doc.get_metadata(MetadataType.TITLE), "New Title")
|
||||
|
||||
|
||||
def test_block_management(self):
|
||||
"""Test adding and managing blocks."""
|
||||
# Create some blocks
|
||||
para1 = Paragraph()
|
||||
para2 = Paragraph()
|
||||
heading = Heading(HeadingLevel.H1)
|
||||
|
||||
|
||||
# Add blocks
|
||||
self.doc.add_block(para1)
|
||||
self.doc.add_block(heading)
|
||||
self.doc.add_block(para2)
|
||||
|
||||
|
||||
# Test blocks list
|
||||
self.assertEqual(len(self.doc.blocks), 3)
|
||||
self.assertEqual(self.doc.blocks[0], para1)
|
||||
self.assertEqual(self.doc.blocks[1], heading)
|
||||
self.assertEqual(self.doc.blocks[2], para2)
|
||||
|
||||
|
||||
def test_anchor_management(self):
|
||||
"""Test named anchor functionality."""
|
||||
heading = Heading(HeadingLevel.H1)
|
||||
para = Paragraph()
|
||||
|
||||
|
||||
# Add anchors
|
||||
self.doc.add_anchor("intro", heading)
|
||||
self.doc.add_anchor("content", para)
|
||||
|
||||
|
||||
# Test retrieval
|
||||
self.assertEqual(self.doc.get_anchor("intro"), heading)
|
||||
self.assertEqual(self.doc.get_anchor("content"), para)
|
||||
self.assertIsNone(self.doc.get_anchor("nonexistent"))
|
||||
|
||||
|
||||
def test_resource_management(self):
|
||||
"""Test document resource management."""
|
||||
# Add various resources
|
||||
self.doc.add_resource("image1", {"type": "image", "path": "test.jpg"})
|
||||
self.doc.add_resource("style1", {"type": "css", "content": "body {}"})
|
||||
|
||||
|
||||
# Test retrieval
|
||||
image = self.doc.get_resource("image1")
|
||||
self.assertEqual(image["type"], "image")
|
||||
self.assertEqual(image["path"], "test.jpg")
|
||||
|
||||
|
||||
style = self.doc.get_resource("style1")
|
||||
self.assertEqual(style["type"], "css")
|
||||
|
||||
|
||||
# Test non-existent resource
|
||||
self.assertIsNone(self.doc.get_resource("nonexistent"))
|
||||
|
||||
|
||||
def test_stylesheet_management(self):
|
||||
"""Test stylesheet addition."""
|
||||
# Add stylesheets
|
||||
css1 = {"href": "style.css", "type": "text/css"}
|
||||
css2 = {"href": "theme.css", "type": "text/css"}
|
||||
|
||||
|
||||
self.doc.add_stylesheet(css1)
|
||||
self.doc.add_stylesheet(css2)
|
||||
|
||||
|
||||
# Test that stylesheets are stored
|
||||
self.assertEqual(len(self.doc._stylesheets), 2)
|
||||
self.assertEqual(self.doc._stylesheets[0], css1)
|
||||
self.assertEqual(self.doc._stylesheets[1], css2)
|
||||
|
||||
|
||||
def test_script_management(self):
|
||||
"""Test script addition."""
|
||||
# Add scripts
|
||||
script1 = "console.log('Hello');"
|
||||
script2 = "document.ready(function(){});"
|
||||
|
||||
|
||||
self.doc.add_script(script1)
|
||||
self.doc.add_script(script2)
|
||||
|
||||
|
||||
# Test that scripts are stored
|
||||
self.assertEqual(len(self.doc._scripts), 2)
|
||||
self.assertEqual(self.doc._scripts[0], script1)
|
||||
self.assertEqual(self.doc._scripts[1], script2)
|
||||
|
||||
|
||||
def test_find_blocks_by_type(self):
|
||||
"""Test finding blocks by type."""
|
||||
# Create blocks of different types
|
||||
@@ -158,87 +164,87 @@ class TestDocument(unittest.TestCase):
|
||||
para2 = Paragraph()
|
||||
heading1 = Heading(HeadingLevel.H1)
|
||||
heading2 = Heading(HeadingLevel.H2)
|
||||
|
||||
|
||||
# Add blocks to document
|
||||
self.doc.add_block(para1)
|
||||
self.doc.add_block(heading1)
|
||||
self.doc.add_block(para2)
|
||||
self.doc.add_block(heading2)
|
||||
|
||||
|
||||
# Test finding paragraphs
|
||||
paragraphs = self.doc.find_blocks_by_type(BlockType.PARAGRAPH)
|
||||
self.assertEqual(len(paragraphs), 2)
|
||||
self.assertIn(para1, paragraphs)
|
||||
self.assertIn(para2, paragraphs)
|
||||
|
||||
|
||||
# Test finding headings
|
||||
headings = self.doc.find_blocks_by_type(BlockType.HEADING)
|
||||
self.assertEqual(len(headings), 2)
|
||||
self.assertIn(heading1, headings)
|
||||
self.assertIn(heading2, headings)
|
||||
|
||||
|
||||
def test_find_headings(self):
|
||||
"""Test finding heading blocks specifically."""
|
||||
# Create mixed blocks
|
||||
para = Paragraph()
|
||||
h1 = Heading(HeadingLevel.H1)
|
||||
h2 = Heading(HeadingLevel.H2)
|
||||
|
||||
|
||||
# Add words to headings for title extraction
|
||||
word1 = Word("Chapter", self.font)
|
||||
word2 = Word("One", self.font)
|
||||
h1.add_word(word1)
|
||||
h1.add_word(word2)
|
||||
|
||||
|
||||
word3 = Word("Section", self.font)
|
||||
h2.add_word(word3)
|
||||
|
||||
|
||||
self.doc.add_block(para)
|
||||
self.doc.add_block(h1)
|
||||
self.doc.add_block(h2)
|
||||
|
||||
|
||||
# Test finding headings
|
||||
headings = self.doc.find_headings()
|
||||
self.assertEqual(len(headings), 2)
|
||||
self.assertIn(h1, headings)
|
||||
self.assertIn(h2, headings)
|
||||
self.assertNotIn(para, headings)
|
||||
|
||||
|
||||
def test_generate_table_of_contents(self):
|
||||
"""Test table of contents generation."""
|
||||
# Create headings with content
|
||||
h1 = Heading(HeadingLevel.H1)
|
||||
h2 = Heading(HeadingLevel.H2)
|
||||
h3 = Heading(HeadingLevel.H3)
|
||||
|
||||
|
||||
# Add words to headings
|
||||
h1.add_word(Word("Introduction", self.font))
|
||||
h2.add_word(Word("Getting", self.font))
|
||||
h2.add_word(Word("Started", self.font))
|
||||
h3.add_word(Word("Installation", self.font))
|
||||
|
||||
|
||||
self.doc.add_block(h1)
|
||||
self.doc.add_block(h2)
|
||||
self.doc.add_block(h3)
|
||||
|
||||
|
||||
# Generate TOC
|
||||
toc = self.doc.generate_table_of_contents()
|
||||
|
||||
|
||||
# Test TOC structure
|
||||
self.assertEqual(len(toc), 3)
|
||||
|
||||
|
||||
# Test first entry
|
||||
level, title, block = toc[0]
|
||||
self.assertEqual(level, 1) # H1
|
||||
self.assertEqual(title, "Introduction")
|
||||
self.assertEqual(block, h1)
|
||||
|
||||
|
||||
# Test second entry
|
||||
level, title, block = toc[1]
|
||||
self.assertEqual(level, 2) # H2
|
||||
self.assertEqual(title, "Getting Started")
|
||||
self.assertEqual(block, h2)
|
||||
|
||||
|
||||
# Test third entry
|
||||
level, title, block = toc[2]
|
||||
self.assertEqual(level, 3) # H3
|
||||
@@ -248,127 +254,127 @@ class TestDocument(unittest.TestCase):
|
||||
|
||||
class TestChapter(unittest.TestCase):
|
||||
"""Test cases for Chapter class."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.chapter = Chapter("Test Chapter", 1)
|
||||
|
||||
|
||||
def test_chapter_creation(self):
|
||||
"""Test chapter creation."""
|
||||
self.assertEqual(self.chapter.title, "Test Chapter")
|
||||
self.assertEqual(self.chapter.level, 1)
|
||||
self.assertEqual(len(self.chapter.blocks), 0)
|
||||
|
||||
|
||||
def test_chapter_creation_minimal(self):
|
||||
"""Test chapter creation with minimal parameters."""
|
||||
chapter = Chapter()
|
||||
self.assertIsNone(chapter.title)
|
||||
self.assertEqual(chapter.level, 1)
|
||||
|
||||
|
||||
def test_title_property(self):
|
||||
"""Test title property getter and setter."""
|
||||
# Test setter
|
||||
self.chapter.title = "New Chapter Title"
|
||||
self.assertEqual(self.chapter.title, "New Chapter Title")
|
||||
|
||||
|
||||
# Test setting to None
|
||||
self.chapter.title = None
|
||||
self.assertIsNone(self.chapter.title)
|
||||
|
||||
|
||||
def test_level_property(self):
|
||||
"""Test level property."""
|
||||
self.assertEqual(self.chapter.level, 1)
|
||||
|
||||
|
||||
# Level should be read-only (no setter test)
|
||||
# This is by design based on the class definition
|
||||
|
||||
|
||||
def test_block_management(self):
|
||||
"""Test adding blocks to chapter."""
|
||||
para1 = Paragraph()
|
||||
para2 = Paragraph()
|
||||
heading = Heading(HeadingLevel.H2)
|
||||
|
||||
|
||||
# Add blocks
|
||||
self.chapter.add_block(para1)
|
||||
self.chapter.add_block(heading)
|
||||
self.chapter.add_block(para2)
|
||||
|
||||
|
||||
# Test blocks list
|
||||
self.assertEqual(len(self.chapter.blocks), 3)
|
||||
self.assertEqual(self.chapter.blocks[0], para1)
|
||||
self.assertEqual(self.chapter.blocks[1], heading)
|
||||
self.assertEqual(self.chapter.blocks[2], para2)
|
||||
|
||||
|
||||
def test_metadata_management(self):
|
||||
"""Test chapter metadata."""
|
||||
# Set metadata
|
||||
self.chapter.set_metadata("author", "Jane Doe")
|
||||
self.chapter.set_metadata("word_count", 1500)
|
||||
self.chapter.set_metadata("tags", ["intro", "basics"])
|
||||
|
||||
|
||||
# Test retrieval
|
||||
self.assertEqual(self.chapter.get_metadata("author"), "Jane Doe")
|
||||
self.assertEqual(self.chapter.get_metadata("word_count"), 1500)
|
||||
self.assertEqual(self.chapter.get_metadata("tags"), ["intro", "basics"])
|
||||
|
||||
|
||||
# Test non-existent metadata
|
||||
self.assertIsNone(self.chapter.get_metadata("nonexistent"))
|
||||
|
||||
|
||||
class TestBook(unittest.TestCase):
|
||||
"""Test cases for Book class."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.book = Book("Test Book", "Author Name", "en-US")
|
||||
|
||||
|
||||
def test_book_creation(self):
|
||||
"""Test book creation with all parameters."""
|
||||
self.assertEqual(self.book.get_title(), "Test Book")
|
||||
self.assertEqual(self.book.get_author(), "Author Name")
|
||||
self.assertEqual(self.book.get_metadata(MetadataType.LANGUAGE), "en-US")
|
||||
self.assertEqual(len(self.book.chapters), 0)
|
||||
|
||||
|
||||
def test_book_creation_minimal(self):
|
||||
"""Test book creation with minimal parameters."""
|
||||
book = Book()
|
||||
self.assertIsNone(book.get_title())
|
||||
self.assertIsNone(book.get_author())
|
||||
self.assertEqual(book.get_metadata(MetadataType.LANGUAGE), "en-US")
|
||||
|
||||
|
||||
def test_book_creation_partial(self):
|
||||
"""Test book creation with partial parameters."""
|
||||
book = Book(title="Just Title")
|
||||
self.assertEqual(book.get_title(), "Just Title")
|
||||
self.assertIsNone(book.get_author())
|
||||
|
||||
|
||||
def test_author_convenience_methods(self):
|
||||
"""Test author getter and setter convenience methods."""
|
||||
# Test setting author
|
||||
self.book.set_author("New Author")
|
||||
self.assertEqual(self.book.get_author(), "New Author")
|
||||
|
||||
|
||||
# Test that it's also in metadata
|
||||
self.assertEqual(self.book.get_metadata(MetadataType.AUTHOR), "New Author")
|
||||
|
||||
|
||||
def test_chapter_management(self):
|
||||
"""Test adding and managing chapters."""
|
||||
# Create chapters
|
||||
ch1 = Chapter("Introduction", 1)
|
||||
ch2 = Chapter("Getting Started", 1)
|
||||
ch3 = Chapter("Advanced Topics", 1)
|
||||
|
||||
|
||||
# Add chapters
|
||||
self.book.add_chapter(ch1)
|
||||
self.book.add_chapter(ch2)
|
||||
self.book.add_chapter(ch3)
|
||||
|
||||
|
||||
# Test chapters list
|
||||
self.assertEqual(len(self.book.chapters), 3)
|
||||
self.assertEqual(self.book.chapters[0], ch1)
|
||||
self.assertEqual(self.book.chapters[1], ch2)
|
||||
self.assertEqual(self.book.chapters[2], ch3)
|
||||
|
||||
|
||||
def test_create_chapter(self):
|
||||
"""Test creating chapters through the book."""
|
||||
# Create chapter with title and level
|
||||
@@ -377,13 +383,13 @@ class TestBook(unittest.TestCase):
|
||||
self.assertEqual(ch1.level, 1)
|
||||
self.assertEqual(len(self.book.chapters), 1)
|
||||
self.assertEqual(self.book.chapters[0], ch1)
|
||||
|
||||
|
||||
# Create chapter with minimal parameters
|
||||
ch2 = self.book.create_chapter()
|
||||
self.assertIsNone(ch2.title)
|
||||
self.assertEqual(ch2.level, 1)
|
||||
self.assertEqual(len(self.book.chapters), 2)
|
||||
|
||||
|
||||
def test_generate_book_toc(self):
|
||||
"""Test table of contents generation for book."""
|
||||
# Create chapters with different levels
|
||||
@@ -392,20 +398,20 @@ class TestBook(unittest.TestCase):
|
||||
ch3 = Chapter("Basic Concepts", 2)
|
||||
ch4 = Chapter("Advanced Topics", 1)
|
||||
ch5 = Chapter("Best Practices", 2)
|
||||
|
||||
|
||||
# Add chapters to book
|
||||
self.book.add_chapter(ch1)
|
||||
self.book.add_chapter(ch2)
|
||||
self.book.add_chapter(ch3)
|
||||
self.book.add_chapter(ch4)
|
||||
self.book.add_chapter(ch5)
|
||||
|
||||
|
||||
# Generate TOC
|
||||
toc = self.book.generate_table_of_contents()
|
||||
|
||||
|
||||
# Test TOC structure
|
||||
self.assertEqual(len(toc), 5)
|
||||
|
||||
|
||||
# Test entries
|
||||
expected = [
|
||||
(1, "Introduction", ch1),
|
||||
@@ -414,38 +420,38 @@ class TestBook(unittest.TestCase):
|
||||
(1, "Advanced Topics", ch4),
|
||||
(2, "Best Practices", ch5)
|
||||
]
|
||||
|
||||
|
||||
for i, (exp_level, exp_title, exp_chapter) in enumerate(expected):
|
||||
level, title, chapter = toc[i]
|
||||
self.assertEqual(level, exp_level)
|
||||
self.assertEqual(title, exp_title)
|
||||
self.assertEqual(chapter, exp_chapter)
|
||||
|
||||
|
||||
def test_generate_book_toc_with_untitled_chapters(self):
|
||||
"""Test TOC generation with chapters that have no title."""
|
||||
# Create chapters, some without titles
|
||||
ch1 = Chapter("Introduction", 1)
|
||||
ch2 = Chapter(None, 1) # No title
|
||||
ch3 = Chapter("Conclusion", 1)
|
||||
|
||||
|
||||
self.book.add_chapter(ch1)
|
||||
self.book.add_chapter(ch2)
|
||||
self.book.add_chapter(ch3)
|
||||
|
||||
|
||||
# Generate TOC
|
||||
toc = self.book.generate_table_of_contents()
|
||||
|
||||
|
||||
# Should only include chapters with titles
|
||||
self.assertEqual(len(toc), 2)
|
||||
|
||||
|
||||
level, title, chapter = toc[0]
|
||||
self.assertEqual(title, "Introduction")
|
||||
self.assertEqual(chapter, ch1)
|
||||
|
||||
|
||||
level, title, chapter = toc[1]
|
||||
self.assertEqual(title, "Conclusion")
|
||||
self.assertEqual(chapter, ch3)
|
||||
|
||||
|
||||
def test_book_inherits_document_features(self):
|
||||
"""Test that Book inherits all Document functionality."""
|
||||
# Test that book can use all document methods
|
||||
@@ -453,11 +459,14 @@ class TestBook(unittest.TestCase):
|
||||
para = Paragraph()
|
||||
self.book.add_block(para)
|
||||
self.assertEqual(len(self.book.blocks), 1)
|
||||
|
||||
|
||||
# Test metadata
|
||||
self.book.set_metadata(MetadataType.PUBLISHER, "Test Publisher")
|
||||
self.assertEqual(self.book.get_metadata(MetadataType.PUBLISHER), "Test Publisher")
|
||||
|
||||
self.assertEqual(
|
||||
self.book.get_metadata(
|
||||
MetadataType.PUBLISHER),
|
||||
"Test Publisher")
|
||||
|
||||
# Test anchors
|
||||
heading = Heading(HeadingLevel.H1)
|
||||
self.book.add_anchor("preface", heading)
|
||||
@@ -466,11 +475,11 @@ class TestBook(unittest.TestCase):
|
||||
|
||||
class TestDocumentFontRegistry(unittest.TestCase):
|
||||
"""Test cases for Document font registry functionality."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.doc = Document("Test Document", "en-US")
|
||||
|
||||
|
||||
def test_get_or_create_font_creates_new_font(self):
|
||||
"""Test that get_or_create_font creates a new font when none exists."""
|
||||
font = self.doc.get_or_create_font(
|
||||
@@ -478,14 +487,14 @@ class TestDocumentFontRegistry(unittest.TestCase):
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(font.font_size, 14)
|
||||
self.assertEqual(font.colour, (255, 0, 0))
|
||||
self.assertEqual(font.weight, FontWeight.BOLD)
|
||||
|
||||
|
||||
# Check that font is stored in registry
|
||||
self.assertEqual(len(self.doc._fonts), 1)
|
||||
|
||||
|
||||
def test_get_or_create_font_reuses_existing_font(self):
|
||||
"""Test that get_or_create_font reuses existing fonts."""
|
||||
# Create first font
|
||||
@@ -494,20 +503,20 @@ class TestDocumentFontRegistry(unittest.TestCase):
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Create second font with same properties
|
||||
font2 = self.doc.get_or_create_font(
|
||||
font_size=14,
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Should return the same font object
|
||||
self.assertIs(font1, font2)
|
||||
|
||||
|
||||
# Should only have one font in registry
|
||||
self.assertEqual(len(self.doc._fonts), 1)
|
||||
|
||||
|
||||
def test_get_or_create_font_creates_different_fonts(self):
|
||||
"""Test that different font properties create different fonts."""
|
||||
# Create first font
|
||||
@@ -516,28 +525,28 @@ class TestDocumentFontRegistry(unittest.TestCase):
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Create font with different size
|
||||
font2 = self.doc.get_or_create_font(
|
||||
font_size=16,
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Create font with different color
|
||||
font3 = self.doc.get_or_create_font(
|
||||
font_size=14,
|
||||
colour=(0, 255, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Create font with different weight
|
||||
font4 = self.doc.get_or_create_font(
|
||||
font_size=14,
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.NORMAL
|
||||
)
|
||||
|
||||
|
||||
# All should be different objects
|
||||
self.assertIsNot(font1, font2)
|
||||
self.assertIsNot(font1, font3)
|
||||
@@ -545,10 +554,10 @@ class TestDocumentFontRegistry(unittest.TestCase):
|
||||
self.assertIsNot(font2, font3)
|
||||
self.assertIsNot(font2, font4)
|
||||
self.assertIsNot(font3, font4)
|
||||
|
||||
|
||||
# Should have four fonts in registry
|
||||
self.assertEqual(len(self.doc._fonts), 4)
|
||||
|
||||
|
||||
def test_get_or_create_font_with_all_parameters(self):
|
||||
"""Test get_or_create_font with all parameters."""
|
||||
font = self.doc.get_or_create_font(
|
||||
@@ -562,7 +571,7 @@ class TestDocumentFontRegistry(unittest.TestCase):
|
||||
language="fr_FR",
|
||||
min_hyphenation_width=80
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(font._font_path, "path/to/font.ttf")
|
||||
self.assertEqual(font.font_size, 18)
|
||||
self.assertEqual(font.colour, (128, 64, 192))
|
||||
@@ -572,11 +581,11 @@ class TestDocumentFontRegistry(unittest.TestCase):
|
||||
self.assertEqual(font.background, (255, 255, 255, 128))
|
||||
self.assertEqual(font.language, "fr_FR")
|
||||
self.assertEqual(font.min_hyphenation_width, 80)
|
||||
|
||||
|
||||
def test_get_or_create_font_with_defaults(self):
|
||||
"""Test get_or_create_font with default values."""
|
||||
font = self.doc.get_or_create_font()
|
||||
|
||||
|
||||
# Should create font with default values
|
||||
self.assertIsNotNone(font)
|
||||
self.assertEqual(font.font_size, 16) # Default font size
|
||||
@@ -588,12 +597,12 @@ class TestDocumentFontRegistry(unittest.TestCase):
|
||||
|
||||
class TestChapterFontRegistry(unittest.TestCase):
|
||||
"""Test cases for Chapter font registry functionality."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.doc = Document("Test Document", "en-US")
|
||||
self.chapter = Chapter("Test Chapter", 1, parent=self.doc)
|
||||
|
||||
|
||||
def test_chapter_uses_parent_font_registry(self):
|
||||
"""Test that chapter uses parent document's font registry."""
|
||||
# Create font through chapter - should delegate to parent
|
||||
@@ -602,52 +611,52 @@ class TestChapterFontRegistry(unittest.TestCase):
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Create same font through document - should return same object
|
||||
font2 = self.doc.get_or_create_font(
|
||||
font_size=14,
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Should be the same font object
|
||||
self.assertIs(font1, font2)
|
||||
|
||||
|
||||
# Should be stored in document's registry, not chapter's
|
||||
self.assertEqual(len(self.doc._fonts), 1)
|
||||
self.assertEqual(len(self.chapter._fonts), 0)
|
||||
|
||||
|
||||
def test_chapter_without_parent_manages_own_fonts(self):
|
||||
"""Test that chapter without parent manages its own fonts."""
|
||||
# Create chapter without parent
|
||||
standalone_chapter = Chapter("Standalone Chapter", 1)
|
||||
|
||||
|
||||
# Create font through chapter
|
||||
font1 = standalone_chapter.get_or_create_font(
|
||||
font_size=14,
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Create same font again - should reuse
|
||||
font2 = standalone_chapter.get_or_create_font(
|
||||
font_size=14,
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Should be the same font object
|
||||
self.assertIs(font1, font2)
|
||||
|
||||
|
||||
# Should be stored in chapter's own registry
|
||||
self.assertEqual(len(standalone_chapter._fonts), 1)
|
||||
|
||||
|
||||
def test_chapter_parent_assignment(self):
|
||||
"""Test that chapter parent assignment works correctly."""
|
||||
# Create chapter with parent
|
||||
chapter_with_parent = Chapter("Chapter with Parent", 1, parent=self.doc)
|
||||
self.assertEqual(chapter_with_parent._parent, self.doc)
|
||||
|
||||
|
||||
# Create chapter without parent
|
||||
chapter_without_parent = Chapter("Chapter without Parent", 1)
|
||||
self.assertIsNone(chapter_without_parent._parent)
|
||||
@@ -655,11 +664,11 @@ class TestChapterFontRegistry(unittest.TestCase):
|
||||
|
||||
class TestBookFontRegistry(unittest.TestCase):
|
||||
"""Test cases for Book font registry functionality."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.book = Book("Test Book", "Author Name", "en-US")
|
||||
|
||||
|
||||
def test_book_inherits_document_font_registry(self):
|
||||
"""Test that Book inherits Document's font registry functionality."""
|
||||
# Create font through book
|
||||
@@ -668,17 +677,17 @@ class TestBookFontRegistry(unittest.TestCase):
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Create same font again - should reuse
|
||||
font2 = self.book.get_or_create_font(
|
||||
font_size=14,
|
||||
colour=(255, 0, 0),
|
||||
weight=FontWeight.BOLD
|
||||
)
|
||||
|
||||
|
||||
# Should be the same font object
|
||||
self.assertIs(font1, font2)
|
||||
|
||||
|
||||
# Should have one font in registry
|
||||
self.assertEqual(len(self.book._fonts), 1)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ interactive functionality and user interface elements.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
from unittest.mock import Mock
|
||||
from pyWebLayout.abstract.functional import (
|
||||
Link, LinkType, Button, Form, FormField, FormFieldType
|
||||
)
|
||||
@@ -14,14 +14,14 @@ from pyWebLayout.abstract.functional import (
|
||||
|
||||
class TestLinkType(unittest.TestCase):
|
||||
"""Test cases for LinkType enum."""
|
||||
|
||||
|
||||
def test_link_types(self):
|
||||
"""Test that all expected link types exist."""
|
||||
expected_types = ['INTERNAL', 'EXTERNAL', 'API', 'FUNCTION']
|
||||
|
||||
|
||||
for type_name in expected_types:
|
||||
self.assertTrue(hasattr(LinkType, type_name))
|
||||
|
||||
|
||||
# Test specific values
|
||||
self.assertEqual(LinkType.INTERNAL.value, 1)
|
||||
self.assertEqual(LinkType.EXTERNAL.value, 2)
|
||||
@@ -31,21 +31,21 @@ class TestLinkType(unittest.TestCase):
|
||||
|
||||
class TestLink(unittest.TestCase):
|
||||
"""Test cases for Link class."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.mock_callback = Mock(return_value="callback_result")
|
||||
|
||||
|
||||
def test_link_creation_minimal(self):
|
||||
"""Test link creation with minimal parameters."""
|
||||
link = Link("test-location")
|
||||
|
||||
|
||||
self.assertEqual(link.location, "test-location")
|
||||
self.assertEqual(link.link_type, LinkType.INTERNAL) # Default
|
||||
self.assertEqual(link.params, {})
|
||||
self.assertIsNone(link.title)
|
||||
self.assertIsNone(link._callback)
|
||||
|
||||
|
||||
def test_link_creation_full(self):
|
||||
"""Test link creation with all parameters."""
|
||||
params = {"param1": "value1", "param2": "value2"}
|
||||
@@ -56,29 +56,29 @@ class TestLink(unittest.TestCase):
|
||||
params=params,
|
||||
title="Example Link"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(link.location, "https://example.com")
|
||||
self.assertEqual(link.link_type, LinkType.EXTERNAL)
|
||||
self.assertEqual(link.params, params)
|
||||
self.assertEqual(link.title, "Example Link")
|
||||
self.assertEqual(link._callback, self.mock_callback)
|
||||
|
||||
|
||||
def test_internal_link_execution(self):
|
||||
"""Test executing internal links."""
|
||||
link = Link("#section1", LinkType.INTERNAL)
|
||||
result = link.execute()
|
||||
|
||||
|
||||
# Internal links should return the location
|
||||
self.assertEqual(result, "#section1")
|
||||
|
||||
|
||||
def test_external_link_execution(self):
|
||||
"""Test executing external links."""
|
||||
link = Link("https://example.com", LinkType.EXTERNAL)
|
||||
result = link.execute()
|
||||
|
||||
|
||||
# External links should return the location
|
||||
self.assertEqual(result, "https://example.com")
|
||||
|
||||
|
||||
def test_api_link_execution(self):
|
||||
"""Test executing API links with callback."""
|
||||
params = {"action": "save", "id": 123}
|
||||
@@ -92,9 +92,10 @@ class TestLink(unittest.TestCase):
|
||||
result = link.execute()
|
||||
|
||||
# Should call callback with location, point (None when not provided), and params
|
||||
self.mock_callback.assert_called_once_with("/api/save", None, action="save", id=123)
|
||||
self.mock_callback.assert_called_once_with(
|
||||
"/api/save", None, action="save", id=123)
|
||||
self.assertEqual(result, "callback_result")
|
||||
|
||||
|
||||
def test_function_link_execution(self):
|
||||
"""Test executing function links with callback."""
|
||||
params = {"data": "test"}
|
||||
@@ -110,23 +111,23 @@ class TestLink(unittest.TestCase):
|
||||
# Should call callback with location, point (None when not provided), and params
|
||||
self.mock_callback.assert_called_once_with("save_document", None, data="test")
|
||||
self.assertEqual(result, "callback_result")
|
||||
|
||||
|
||||
def test_api_link_without_callback(self):
|
||||
"""Test API link without callback returns location."""
|
||||
link = Link("/api/endpoint", LinkType.API)
|
||||
result = link.execute()
|
||||
|
||||
|
||||
# Without callback, should return location
|
||||
self.assertEqual(result, "/api/endpoint")
|
||||
|
||||
|
||||
def test_function_link_without_callback(self):
|
||||
"""Test function link without callback returns location."""
|
||||
link = Link("function_name", LinkType.FUNCTION)
|
||||
result = link.execute()
|
||||
|
||||
|
||||
# Without callback, should return location
|
||||
self.assertEqual(result, "function_name")
|
||||
|
||||
|
||||
def test_link_properties(self):
|
||||
"""Test link property access."""
|
||||
params = {"key": "value"}
|
||||
@@ -136,7 +137,7 @@ class TestLink(unittest.TestCase):
|
||||
params=params,
|
||||
title="Test Title"
|
||||
)
|
||||
|
||||
|
||||
# Test all property getters
|
||||
self.assertEqual(link.location, "test")
|
||||
self.assertEqual(link.link_type, LinkType.API)
|
||||
@@ -146,20 +147,20 @@ class TestLink(unittest.TestCase):
|
||||
|
||||
class TestButton(unittest.TestCase):
|
||||
"""Test cases for Button class."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.mock_callback = Mock(return_value="button_clicked")
|
||||
|
||||
|
||||
def test_button_creation_minimal(self):
|
||||
"""Test button creation with minimal parameters."""
|
||||
button = Button("Click Me", self.mock_callback)
|
||||
|
||||
|
||||
self.assertEqual(button.label, "Click Me")
|
||||
self.assertEqual(button._callback, self.mock_callback)
|
||||
self.assertEqual(button.params, {})
|
||||
self.assertTrue(button.enabled)
|
||||
|
||||
|
||||
def test_button_creation_full(self):
|
||||
"""Test button creation with all parameters."""
|
||||
params = {"action": "submit", "form_id": "test_form"}
|
||||
@@ -169,37 +170,37 @@ class TestButton(unittest.TestCase):
|
||||
params=params,
|
||||
enabled=False
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(button.label, "Submit")
|
||||
self.assertEqual(button._callback, self.mock_callback)
|
||||
self.assertEqual(button.params, params)
|
||||
self.assertFalse(button.enabled)
|
||||
|
||||
|
||||
def test_button_label_property(self):
|
||||
"""Test button label getter and setter."""
|
||||
button = Button("Original", self.mock_callback)
|
||||
|
||||
|
||||
# Test getter
|
||||
self.assertEqual(button.label, "Original")
|
||||
|
||||
|
||||
# Test setter
|
||||
button.label = "New Label"
|
||||
self.assertEqual(button.label, "New Label")
|
||||
|
||||
|
||||
def test_button_enabled_property(self):
|
||||
"""Test button enabled getter and setter."""
|
||||
button = Button("Test", self.mock_callback, enabled=True)
|
||||
|
||||
|
||||
# Test initial state
|
||||
self.assertTrue(button.enabled)
|
||||
|
||||
|
||||
# Test setter
|
||||
button.enabled = False
|
||||
self.assertFalse(button.enabled)
|
||||
|
||||
|
||||
button.enabled = True
|
||||
self.assertTrue(button.enabled)
|
||||
|
||||
|
||||
def test_button_execute_enabled(self):
|
||||
"""Test executing enabled button."""
|
||||
params = {"data": "test_data"}
|
||||
@@ -210,40 +211,40 @@ class TestButton(unittest.TestCase):
|
||||
# Should call callback with point (None when not provided) and params
|
||||
self.mock_callback.assert_called_once_with(None, data="test_data")
|
||||
self.assertEqual(result, "button_clicked")
|
||||
|
||||
|
||||
def test_button_execute_disabled(self):
|
||||
"""Test executing disabled button."""
|
||||
button = Button("Test", self.mock_callback, enabled=False)
|
||||
|
||||
|
||||
result = button.execute()
|
||||
|
||||
|
||||
# Should not call callback and return None
|
||||
self.mock_callback.assert_not_called()
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
def test_button_execute_no_callback(self):
|
||||
"""Test executing button without callback."""
|
||||
button = Button("Test", None, enabled=True)
|
||||
|
||||
|
||||
result = button.execute()
|
||||
|
||||
|
||||
# Should return None
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestFormFieldType(unittest.TestCase):
|
||||
"""Test cases for FormFieldType enum."""
|
||||
|
||||
|
||||
def test_form_field_types(self):
|
||||
"""Test that all expected form field types exist."""
|
||||
expected_types = [
|
||||
'TEXT', 'PASSWORD', 'CHECKBOX', 'RADIO', 'SELECT', 'TEXTAREA',
|
||||
'NUMBER', 'DATE', 'TIME', 'EMAIL', 'URL', 'COLOR', 'RANGE', 'HIDDEN'
|
||||
]
|
||||
|
||||
|
||||
for type_name in expected_types:
|
||||
self.assertTrue(hasattr(FormFieldType, type_name))
|
||||
|
||||
|
||||
# Test some specific values
|
||||
self.assertEqual(FormFieldType.TEXT.value, 1)
|
||||
self.assertEqual(FormFieldType.PASSWORD.value, 2)
|
||||
@@ -252,11 +253,11 @@ class TestFormFieldType(unittest.TestCase):
|
||||
|
||||
class TestFormField(unittest.TestCase):
|
||||
"""Test cases for FormField class."""
|
||||
|
||||
|
||||
def test_form_field_creation_minimal(self):
|
||||
"""Test form field creation with minimal parameters."""
|
||||
field = FormField("username", FormFieldType.TEXT)
|
||||
|
||||
|
||||
self.assertEqual(field.name, "username")
|
||||
self.assertEqual(field.field_type, FormFieldType.TEXT)
|
||||
self.assertEqual(field.label, "username") # Default to name
|
||||
@@ -264,7 +265,7 @@ class TestFormField(unittest.TestCase):
|
||||
self.assertFalse(field.required)
|
||||
self.assertEqual(field.options, [])
|
||||
self.assertIsNone(field.form)
|
||||
|
||||
|
||||
def test_form_field_creation_full(self):
|
||||
"""Test form field creation with all parameters."""
|
||||
options = [("value1", "Label 1"), ("value2", "Label 2")]
|
||||
@@ -276,37 +277,37 @@ class TestFormField(unittest.TestCase):
|
||||
required=True,
|
||||
options=options
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(field.name, "country")
|
||||
self.assertEqual(field.field_type, FormFieldType.SELECT)
|
||||
self.assertEqual(field.label, "Country")
|
||||
self.assertEqual(field.value, "value1")
|
||||
self.assertTrue(field.required)
|
||||
self.assertEqual(field.options, options)
|
||||
|
||||
|
||||
def test_form_field_value_property(self):
|
||||
"""Test form field value getter and setter."""
|
||||
field = FormField("test", FormFieldType.TEXT, value="initial")
|
||||
|
||||
|
||||
# Test getter
|
||||
self.assertEqual(field.value, "initial")
|
||||
|
||||
|
||||
# Test setter
|
||||
field.value = "new_value"
|
||||
self.assertEqual(field.value, "new_value")
|
||||
|
||||
|
||||
def test_form_field_form_property(self):
|
||||
"""Test form field form getter and setter."""
|
||||
field = FormField("test", FormFieldType.TEXT)
|
||||
mock_form = Mock()
|
||||
|
||||
|
||||
# Initial state
|
||||
self.assertIsNone(field.form)
|
||||
|
||||
|
||||
# Test setter
|
||||
field.form = mock_form
|
||||
self.assertEqual(field.form, mock_form)
|
||||
|
||||
|
||||
def test_form_field_properties(self):
|
||||
"""Test all form field property getters."""
|
||||
options = [("opt1", "Option 1")]
|
||||
@@ -318,7 +319,7 @@ class TestFormField(unittest.TestCase):
|
||||
required=True,
|
||||
options=options
|
||||
)
|
||||
|
||||
|
||||
# Test all getters
|
||||
self.assertEqual(field.name, "test_field")
|
||||
self.assertEqual(field.field_type, FormFieldType.CHECKBOX)
|
||||
@@ -330,20 +331,20 @@ class TestFormField(unittest.TestCase):
|
||||
|
||||
class TestForm(unittest.TestCase):
|
||||
"""Test cases for Form class."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.mock_callback = Mock(return_value="form_submitted")
|
||||
|
||||
|
||||
def test_form_creation_minimal(self):
|
||||
"""Test form creation with minimal parameters."""
|
||||
form = Form("test_form")
|
||||
|
||||
|
||||
self.assertEqual(form.form_id, "test_form")
|
||||
self.assertIsNone(form.action)
|
||||
self.assertIsNone(form._callback)
|
||||
self.assertEqual(len(form._fields), 0)
|
||||
|
||||
|
||||
def test_form_creation_full(self):
|
||||
"""Test form creation with all parameters."""
|
||||
form = Form(
|
||||
@@ -351,145 +352,144 @@ class TestForm(unittest.TestCase):
|
||||
action="/submit",
|
||||
callback=self.mock_callback
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(form.form_id, "contact_form")
|
||||
self.assertEqual(form.action, "/submit")
|
||||
self.assertEqual(form._callback, self.mock_callback)
|
||||
|
||||
|
||||
def test_form_field_management(self):
|
||||
"""Test adding and retrieving form fields."""
|
||||
form = Form("test_form")
|
||||
|
||||
|
||||
# Create fields
|
||||
field1 = FormField("username", FormFieldType.TEXT, value="john")
|
||||
field2 = FormField("password", FormFieldType.PASSWORD, value="secret")
|
||||
field3 = FormField("email", FormFieldType.EMAIL, value="john@example.com")
|
||||
|
||||
|
||||
# Add fields
|
||||
form.add_field(field1)
|
||||
form.add_field(field2)
|
||||
form.add_field(field3)
|
||||
|
||||
|
||||
# Test that fields are stored correctly
|
||||
self.assertEqual(len(form._fields), 3)
|
||||
|
||||
|
||||
# Test field retrieval
|
||||
self.assertEqual(form.get_field("username"), field1)
|
||||
self.assertEqual(form.get_field("password"), field2)
|
||||
self.assertEqual(form.get_field("email"), field3)
|
||||
self.assertIsNone(form.get_field("nonexistent"))
|
||||
|
||||
|
||||
# Test that fields have form reference
|
||||
self.assertEqual(field1.form, form)
|
||||
self.assertEqual(field2.form, form)
|
||||
self.assertEqual(field3.form, form)
|
||||
|
||||
|
||||
def test_form_get_values(self):
|
||||
"""Test getting form values."""
|
||||
form = Form("test_form")
|
||||
|
||||
|
||||
# Add fields with values
|
||||
form.add_field(FormField("name", FormFieldType.TEXT, value="John Doe"))
|
||||
form.add_field(FormField("age", FormFieldType.NUMBER, value=30))
|
||||
form.add_field(FormField("subscribe", FormFieldType.CHECKBOX, value=True))
|
||||
|
||||
|
||||
# Get values
|
||||
values = form.get_values()
|
||||
|
||||
|
||||
expected = {
|
||||
"name": "John Doe",
|
||||
"age": 30,
|
||||
"subscribe": True
|
||||
}
|
||||
|
||||
|
||||
self.assertEqual(values, expected)
|
||||
|
||||
|
||||
def test_form_get_values_empty(self):
|
||||
"""Test getting values from empty form."""
|
||||
form = Form("empty_form")
|
||||
values = form.get_values()
|
||||
|
||||
|
||||
self.assertEqual(values, {})
|
||||
|
||||
|
||||
def test_form_execute_with_callback(self):
|
||||
"""Test executing form with callback."""
|
||||
form = Form("test_form", callback=self.mock_callback)
|
||||
|
||||
|
||||
# Add some fields
|
||||
form.add_field(FormField("field1", FormFieldType.TEXT, value="value1"))
|
||||
form.add_field(FormField("field2", FormFieldType.TEXT, value="value2"))
|
||||
|
||||
|
||||
result = form.execute()
|
||||
|
||||
|
||||
# Should call callback with form_id and values
|
||||
expected_values = {"field1": "value1", "field2": "value2"}
|
||||
self.mock_callback.assert_called_once_with("test_form", expected_values)
|
||||
self.assertEqual(result, "form_submitted")
|
||||
|
||||
|
||||
def test_form_execute_without_callback(self):
|
||||
"""Test executing form without callback."""
|
||||
form = Form("test_form")
|
||||
|
||||
|
||||
# Add a field
|
||||
form.add_field(FormField("test", FormFieldType.TEXT, value="test_value"))
|
||||
|
||||
|
||||
result = form.execute()
|
||||
|
||||
|
||||
# Should return the form values
|
||||
expected = {"test": "test_value"}
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
|
||||
def test_form_properties(self):
|
||||
"""Test form property getters."""
|
||||
form = Form("test_form", action="/submit")
|
||||
|
||||
|
||||
self.assertEqual(form.form_id, "test_form")
|
||||
self.assertEqual(form.action, "/submit")
|
||||
|
||||
|
||||
class TestFormIntegration(unittest.TestCase):
|
||||
"""Integration tests for form functionality."""
|
||||
|
||||
|
||||
def test_complete_form_workflow(self):
|
||||
"""Test a complete form creation and submission workflow."""
|
||||
# Create form
|
||||
form = Form("registration_form", action="/register")
|
||||
|
||||
|
||||
# Add various field types
|
||||
form.add_field(FormField(
|
||||
"username", FormFieldType.TEXT,
|
||||
"username", FormFieldType.TEXT,
|
||||
label="Username", required=True, value="testuser"
|
||||
))
|
||||
|
||||
|
||||
form.add_field(FormField(
|
||||
"password", FormFieldType.PASSWORD,
|
||||
label="Password", required=True, value="secret123"
|
||||
))
|
||||
|
||||
|
||||
form.add_field(FormField(
|
||||
"email", FormFieldType.EMAIL,
|
||||
label="Email", required=True, value="test@example.com"
|
||||
))
|
||||
|
||||
form.add_field(FormField(
|
||||
"country", FormFieldType.SELECT,
|
||||
label="Country", value="US",
|
||||
options=[("US", "United States"), ("CA", "Canada"), ("UK", "United Kingdom")]
|
||||
))
|
||||
|
||||
|
||||
form.add_field(
|
||||
FormField(
|
||||
"country", FormFieldType.SELECT, label="Country", value="US", options=[
|
||||
("US", "United States"), ("CA", "Canada"), ("UK", "United Kingdom")]))
|
||||
|
||||
form.add_field(FormField(
|
||||
"newsletter", FormFieldType.CHECKBOX,
|
||||
label="Subscribe to newsletter", value=True
|
||||
))
|
||||
|
||||
|
||||
# Test form state
|
||||
self.assertEqual(len(form._fields), 5)
|
||||
|
||||
|
||||
# Test individual field access
|
||||
username_field = form.get_field("username")
|
||||
self.assertEqual(username_field.value, "testuser")
|
||||
self.assertTrue(username_field.required)
|
||||
|
||||
|
||||
# Test getting all values
|
||||
values = form.get_values()
|
||||
expected = {
|
||||
@@ -500,26 +500,26 @@ class TestFormIntegration(unittest.TestCase):
|
||||
"newsletter": True
|
||||
}
|
||||
self.assertEqual(values, expected)
|
||||
|
||||
|
||||
# Test form submission
|
||||
result = form.execute()
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
|
||||
def test_form_field_modification(self):
|
||||
"""Test modifying form fields after creation."""
|
||||
form = Form("test_form")
|
||||
|
||||
|
||||
# Add field
|
||||
field = FormField("test", FormFieldType.TEXT, value="initial")
|
||||
form.add_field(field)
|
||||
|
||||
|
||||
# Modify field value
|
||||
field.value = "modified"
|
||||
|
||||
|
||||
# Test that form reflects the change
|
||||
values = form.get_values()
|
||||
self.assertEqual(values["test"], "modified")
|
||||
|
||||
|
||||
# Test getting the modified field
|
||||
retrieved_field = form.get_field("test")
|
||||
self.assertEqual(retrieved_field.value, "modified")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,9 @@ class TestChapterFontRegistry(FontRegistryTestMixin, unittest.TestCase):
|
||||
return Chapter("Test Chapter", level=1)
|
||||
|
||||
|
||||
class TestChapterFontRegistryParentDelegation(FontRegistryParentDelegationTestMixin, unittest.TestCase):
|
||||
class TestChapterFontRegistryParentDelegation(
|
||||
FontRegistryParentDelegationTestMixin,
|
||||
unittest.TestCase):
|
||||
"""Test FontRegistry parent delegation for Chapter - simplified with mixin."""
|
||||
|
||||
def create_parent(self):
|
||||
|
||||
@@ -3,20 +3,20 @@ Unit tests for LinkedWord and LinkedImage classes.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from pyWebLayout.abstract.inline import Word, LinkedWord
|
||||
from pyWebLayout.abstract.block import Image, LinkedImage
|
||||
from pyWebLayout.abstract.inline import LinkedWord
|
||||
from pyWebLayout.abstract.block import LinkedImage
|
||||
from pyWebLayout.abstract.functional import LinkType
|
||||
from pyWebLayout.style import Font
|
||||
|
||||
|
||||
class TestLinkedWord(unittest.TestCase):
|
||||
"""Test cases for LinkedWord class."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.font = Font(font_size=16)
|
||||
self.location = "https://example.com"
|
||||
|
||||
|
||||
def test_linked_word_creation(self):
|
||||
"""Test creating a LinkedWord."""
|
||||
linked_word = LinkedWord(
|
||||
@@ -25,12 +25,12 @@ class TestLinkedWord(unittest.TestCase):
|
||||
location=self.location,
|
||||
link_type=LinkType.EXTERNAL
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(linked_word.text, "example")
|
||||
self.assertEqual(linked_word.location, self.location)
|
||||
self.assertEqual(linked_word.link_type, LinkType.EXTERNAL)
|
||||
self.assertIsNone(linked_word.link_callback)
|
||||
|
||||
|
||||
def test_linked_word_inherits_from_word(self):
|
||||
"""Test that LinkedWord inherits Word properties."""
|
||||
linked_word = LinkedWord(
|
||||
@@ -38,21 +38,21 @@ class TestLinkedWord(unittest.TestCase):
|
||||
style=self.font,
|
||||
location=self.location
|
||||
)
|
||||
|
||||
|
||||
# Should have Word properties
|
||||
self.assertEqual(linked_word.text, "test")
|
||||
self.assertEqual(linked_word.style, self.font)
|
||||
self.assertIsNone(linked_word.previous)
|
||||
self.assertIsNone(linked_word.next)
|
||||
|
||||
|
||||
def test_linked_word_with_callback(self):
|
||||
"""Test LinkedWord with a callback function."""
|
||||
callback_called = []
|
||||
|
||||
|
||||
def test_callback(location, **params):
|
||||
callback_called.append((location, params))
|
||||
return "navigated"
|
||||
|
||||
|
||||
linked_word = LinkedWord(
|
||||
text="click",
|
||||
style=self.font,
|
||||
@@ -61,15 +61,15 @@ class TestLinkedWord(unittest.TestCase):
|
||||
callback=test_callback,
|
||||
params={"source": "test"}
|
||||
)
|
||||
|
||||
result = linked_word.execute_link()
|
||||
|
||||
|
||||
linked_word.execute_link()
|
||||
|
||||
self.assertEqual(len(callback_called), 1)
|
||||
self.assertEqual(callback_called[0][0], self.location)
|
||||
self.assertIn("text", callback_called[0][1])
|
||||
self.assertEqual(callback_called[0][1]["text"], "click")
|
||||
self.assertEqual(callback_called[0][1]["source"], "test")
|
||||
|
||||
|
||||
def test_linked_word_execute_external_link(self):
|
||||
"""Test executing an external link returns the location."""
|
||||
linked_word = LinkedWord(
|
||||
@@ -78,10 +78,10 @@ class TestLinkedWord(unittest.TestCase):
|
||||
location=self.location,
|
||||
link_type=LinkType.EXTERNAL
|
||||
)
|
||||
|
||||
|
||||
result = linked_word.execute_link()
|
||||
self.assertEqual(result, self.location)
|
||||
|
||||
|
||||
def test_linked_word_with_title(self):
|
||||
"""Test LinkedWord with title/tooltip."""
|
||||
linked_word = LinkedWord(
|
||||
@@ -90,9 +90,9 @@ class TestLinkedWord(unittest.TestCase):
|
||||
location=self.location,
|
||||
title="Click to visit example.com"
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(linked_word.link_title, "Click to visit example.com")
|
||||
|
||||
|
||||
def test_linked_word_chain(self):
|
||||
"""Test chaining multiple LinkedWords."""
|
||||
word1 = LinkedWord(
|
||||
@@ -100,14 +100,14 @@ class TestLinkedWord(unittest.TestCase):
|
||||
style=self.font,
|
||||
location=self.location
|
||||
)
|
||||
|
||||
|
||||
word2 = LinkedWord(
|
||||
text="here",
|
||||
style=self.font,
|
||||
location=self.location,
|
||||
previous=word1
|
||||
)
|
||||
|
||||
|
||||
# Check chain
|
||||
self.assertEqual(word1.next, word2)
|
||||
self.assertEqual(word2.previous, word1)
|
||||
@@ -115,13 +115,13 @@ class TestLinkedWord(unittest.TestCase):
|
||||
|
||||
class TestLinkedImage(unittest.TestCase):
|
||||
"""Test cases for LinkedImage class."""
|
||||
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test fixtures."""
|
||||
self.source = "logo.png"
|
||||
self.alt_text = "Company Logo"
|
||||
self.location = "https://example.com/home"
|
||||
|
||||
|
||||
def test_linked_image_creation(self):
|
||||
"""Test creating a LinkedImage."""
|
||||
linked_image = LinkedImage(
|
||||
@@ -132,14 +132,14 @@ class TestLinkedImage(unittest.TestCase):
|
||||
height=50,
|
||||
link_type=LinkType.EXTERNAL
|
||||
)
|
||||
|
||||
|
||||
self.assertEqual(linked_image.source, self.source)
|
||||
self.assertEqual(linked_image.alt_text, self.alt_text)
|
||||
self.assertEqual(linked_image.location, self.location)
|
||||
self.assertEqual(linked_image.width, 100)
|
||||
self.assertEqual(linked_image.height, 50)
|
||||
self.assertEqual(linked_image.link_type, LinkType.EXTERNAL)
|
||||
|
||||
|
||||
def test_linked_image_inherits_from_image(self):
|
||||
"""Test that LinkedImage inherits Image properties."""
|
||||
linked_image = LinkedImage(
|
||||
@@ -147,20 +147,20 @@ class TestLinkedImage(unittest.TestCase):
|
||||
alt_text=self.alt_text,
|
||||
location=self.location
|
||||
)
|
||||
|
||||
|
||||
# Should have Image properties and methods
|
||||
self.assertEqual(linked_image.source, self.source)
|
||||
self.assertEqual(linked_image.alt_text, self.alt_text)
|
||||
self.assertIsNotNone(linked_image.get_dimensions)
|
||||
|
||||
|
||||
def test_linked_image_with_callback(self):
|
||||
"""Test LinkedImage with a callback function."""
|
||||
callback_called = []
|
||||
|
||||
|
||||
def image_callback(location, **params):
|
||||
callback_called.append((location, params))
|
||||
return "image_clicked"
|
||||
|
||||
|
||||
linked_image = LinkedImage(
|
||||
source=self.source,
|
||||
alt_text=self.alt_text,
|
||||
@@ -168,15 +168,15 @@ class TestLinkedImage(unittest.TestCase):
|
||||
link_type=LinkType.FUNCTION,
|
||||
callback=image_callback
|
||||
)
|
||||
|
||||
result = linked_image.execute_link()
|
||||
|
||||
|
||||
linked_image.execute_link()
|
||||
|
||||
self.assertEqual(len(callback_called), 1)
|
||||
self.assertEqual(callback_called[0][0], self.location)
|
||||
self.assertIn("alt_text", callback_called[0][1])
|
||||
self.assertEqual(callback_called[0][1]["alt_text"], self.alt_text)
|
||||
self.assertIn("source", callback_called[0][1])
|
||||
|
||||
|
||||
def test_linked_image_execute_internal_link(self):
|
||||
"""Test executing an internal link returns the location."""
|
||||
linked_image = LinkedImage(
|
||||
@@ -185,7 +185,7 @@ class TestLinkedImage(unittest.TestCase):
|
||||
location="#section2",
|
||||
link_type=LinkType.INTERNAL
|
||||
)
|
||||
|
||||
|
||||
result = linked_image.execute_link()
|
||||
self.assertEqual(result, "#section2")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user