469 lines
17 KiB
Python
469 lines
17 KiB
Python
"""
|
|
Unit tests for abstract document elements.
|
|
|
|
Tests the Document, Chapter, Book, and MetadataType classes that handle
|
|
document structure and metadata management.
|
|
"""
|
|
|
|
import unittest
|
|
from pyWebLayout.abstract.document import Document, Chapter, Book, MetadataType
|
|
from pyWebLayout.abstract.block import Parapgraph, Heading, HeadingLevel, BlockType
|
|
from pyWebLayout.abstract.inline import Word, FormattedSpan
|
|
from pyWebLayout.style import Font
|
|
|
|
|
|
class TestMetadataType(unittest.TestCase):
|
|
"""Test cases for MetadataType enum."""
|
|
|
|
def test_metadata_types(self):
|
|
"""Test that all expected metadata types exist."""
|
|
expected_types = [
|
|
'TITLE', 'AUTHOR', 'DESCRIPTION', 'KEYWORDS', 'LANGUAGE',
|
|
'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"])
|
|
|
|
# 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 = Parapgraph()
|
|
para2 = Parapgraph()
|
|
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 = Parapgraph()
|
|
|
|
# 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
|
|
para1 = Parapgraph()
|
|
para2 = Parapgraph()
|
|
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 = Parapgraph()
|
|
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
|
|
self.assertEqual(title, "Installation")
|
|
self.assertEqual(block, h3)
|
|
|
|
|
|
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 = Parapgraph()
|
|
para2 = Parapgraph()
|
|
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
|
|
ch1 = self.book.create_chapter("Chapter 1", 1)
|
|
self.assertEqual(ch1.title, "Chapter 1")
|
|
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
|
|
ch1 = Chapter("Introduction", 1)
|
|
ch2 = Chapter("Getting Started", 1)
|
|
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),
|
|
(1, "Getting Started", ch2),
|
|
(2, "Basic Concepts", ch3),
|
|
(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
|
|
# Add blocks directly to book
|
|
para = Parapgraph()
|
|
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")
|
|
|
|
# Test anchors
|
|
heading = Heading(HeadingLevel.H1)
|
|
self.book.add_anchor("preface", heading)
|
|
self.assertEqual(self.book.get_anchor("preface"), heading)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|