183 lines
7.7 KiB
Python
183 lines
7.7 KiB
Python
"""
|
|
Unit tests for HTML style management.
|
|
|
|
Tests the HTMLStyleManager class for CSS parsing, style stacks, and font creation.
|
|
"""
|
|
|
|
import unittest
|
|
from pyWebLayout.io.readers.html_style import HTMLStyleManager
|
|
from pyWebLayout.style import FontStyle, FontWeight, TextDecoration
|
|
|
|
|
|
class TestHTMLStyleManager(unittest.TestCase):
|
|
"""Test cases for HTMLStyleManager."""
|
|
|
|
def setUp(self):
|
|
"""Set up test fixtures."""
|
|
self.style_manager = HTMLStyleManager()
|
|
|
|
def test_initialization(self):
|
|
"""Test proper initialization of style manager."""
|
|
style = self.style_manager.get_current_style()
|
|
|
|
self.assertEqual(style['font_size'], 12)
|
|
self.assertEqual(style['font_weight'], FontWeight.NORMAL)
|
|
self.assertEqual(style['font_style'], FontStyle.NORMAL)
|
|
self.assertEqual(style['decoration'], TextDecoration.NONE)
|
|
self.assertEqual(style['color'], (0, 0, 0))
|
|
self.assertIsNone(style['background'])
|
|
self.assertEqual(style['language'], 'en_US')
|
|
|
|
def test_style_stack_operations(self):
|
|
"""Test push and pop operations on style stack."""
|
|
# Initial state
|
|
initial_style = self.style_manager.get_current_style()
|
|
|
|
# Push a new style
|
|
new_style = {'font_size': 16, 'font_weight': FontWeight.BOLD}
|
|
self.style_manager.push_style(new_style)
|
|
|
|
current_style = self.style_manager.get_current_style()
|
|
self.assertEqual(current_style['font_size'], 16)
|
|
self.assertEqual(current_style['font_weight'], FontWeight.BOLD)
|
|
self.assertEqual(current_style['color'], (0, 0, 0)) # Unchanged
|
|
|
|
# Pop the style
|
|
self.style_manager.pop_style()
|
|
restored_style = self.style_manager.get_current_style()
|
|
self.assertEqual(restored_style, initial_style)
|
|
|
|
def test_tag_styles(self):
|
|
"""Test default styles for HTML tags."""
|
|
h1_style = self.style_manager.get_tag_style('h1')
|
|
self.assertEqual(h1_style['font_size'], 24)
|
|
self.assertEqual(h1_style['font_weight'], FontWeight.BOLD)
|
|
|
|
h6_style = self.style_manager.get_tag_style('h6')
|
|
self.assertEqual(h6_style['font_size'], 12)
|
|
self.assertEqual(h6_style['font_weight'], FontWeight.BOLD)
|
|
|
|
em_style = self.style_manager.get_tag_style('em')
|
|
self.assertEqual(em_style['font_style'], FontStyle.ITALIC)
|
|
|
|
unknown_style = self.style_manager.get_tag_style('unknown')
|
|
self.assertEqual(unknown_style, {})
|
|
|
|
def test_inline_style_parsing(self):
|
|
"""Test parsing of inline CSS styles."""
|
|
# Test font-size
|
|
style = self.style_manager.parse_inline_style('font-size: 18px')
|
|
self.assertEqual(style['font_size'], 18)
|
|
|
|
style = self.style_manager.parse_inline_style('font-size: 14pt')
|
|
self.assertEqual(style['font_size'], 14)
|
|
|
|
# Test font-weight
|
|
style = self.style_manager.parse_inline_style('font-weight: bold')
|
|
self.assertEqual(style['font_weight'], FontWeight.BOLD)
|
|
|
|
# Test font-style
|
|
style = self.style_manager.parse_inline_style('font-style: italic')
|
|
self.assertEqual(style['font_style'], FontStyle.ITALIC)
|
|
|
|
# Test text-decoration
|
|
style = self.style_manager.parse_inline_style('text-decoration: underline')
|
|
self.assertEqual(style['decoration'], TextDecoration.UNDERLINE)
|
|
|
|
# Test multiple properties
|
|
style = self.style_manager.parse_inline_style(
|
|
'font-size: 20px; font-weight: bold; color: red'
|
|
)
|
|
self.assertEqual(style['font_size'], 20)
|
|
self.assertEqual(style['font_weight'], FontWeight.BOLD)
|
|
self.assertEqual(style['color'], (255, 0, 0))
|
|
|
|
def test_color_parsing(self):
|
|
"""Test CSS color parsing."""
|
|
# Named colors
|
|
self.assertEqual(self.style_manager.parse_color('red'), (255, 0, 0))
|
|
self.assertEqual(self.style_manager.parse_color('blue'), (0, 0, 255))
|
|
self.assertEqual(self.style_manager.parse_color('white'), (255, 255, 255))
|
|
self.assertEqual(self.style_manager.parse_color('gray'), (128, 128, 128))
|
|
self.assertEqual(self.style_manager.parse_color('grey'), (128, 128, 128))
|
|
|
|
# Hex colors
|
|
self.assertEqual(self.style_manager.parse_color('#ff0000'), (255, 0, 0))
|
|
self.assertEqual(self.style_manager.parse_color('#00ff00'), (0, 255, 0))
|
|
self.assertEqual(self.style_manager.parse_color('#f00'), (255, 0, 0))
|
|
self.assertEqual(self.style_manager.parse_color('#0f0'), (0, 255, 0))
|
|
|
|
# RGB colors
|
|
self.assertEqual(self.style_manager.parse_color('rgb(255, 0, 0)'), (255, 0, 0))
|
|
self.assertEqual(self.style_manager.parse_color('rgb(128, 128, 128)'), (128, 128, 128))
|
|
self.assertEqual(self.style_manager.parse_color('rgb( 255 , 255 , 255 )'), (255, 255, 255))
|
|
|
|
# RGBA colors (alpha ignored)
|
|
self.assertEqual(self.style_manager.parse_color('rgba(255, 0, 0, 0.5)'), (255, 0, 0))
|
|
|
|
# Invalid colors
|
|
self.assertIsNone(self.style_manager.parse_color('invalid'))
|
|
self.assertIsNone(self.style_manager.parse_color('#gg0000'))
|
|
self.assertIsNone(self.style_manager.parse_color('rgb(300, 0, 0)')) # Invalid values return None
|
|
|
|
def test_color_clamping(self):
|
|
"""Test that RGB values outside valid range return None."""
|
|
# Values outside 0-255 range should return None
|
|
color = self.style_manager.parse_color('rgb(300, -10, 128)')
|
|
self.assertIsNone(color) # Invalid values return None
|
|
|
|
def test_apply_style_to_element(self):
|
|
"""Test combining tag styles with inline styles."""
|
|
# Test h1 with inline style
|
|
attrs = {'style': 'color: blue; font-size: 30px'}
|
|
combined = self.style_manager.apply_style_to_element('h1', attrs)
|
|
|
|
# Should have h1 defaults plus inline overrides
|
|
self.assertEqual(combined['font_size'], 30) # Overridden
|
|
self.assertEqual(combined['font_weight'], FontWeight.BOLD) # From h1
|
|
self.assertEqual(combined['color'], (0, 0, 255)) # Inline
|
|
|
|
# Test without inline styles
|
|
combined = self.style_manager.apply_style_to_element('strong', {})
|
|
self.assertEqual(combined['font_weight'], FontWeight.BOLD)
|
|
|
|
def test_reset(self):
|
|
"""Test resetting the style manager."""
|
|
# Change the state
|
|
self.style_manager.push_style({'font_size': 20})
|
|
self.style_manager.push_style({'color': (255, 0, 0)})
|
|
|
|
# Reset
|
|
self.style_manager.reset()
|
|
|
|
# Should be back to initial state
|
|
style = self.style_manager.get_current_style()
|
|
self.assertEqual(style['font_size'], 12)
|
|
self.assertEqual(style['color'], (0, 0, 0))
|
|
self.assertEqual(len(self.style_manager._style_stack), 0)
|
|
|
|
def test_font_creation(self):
|
|
"""Test Font object creation from current style."""
|
|
# Set some specific styles
|
|
self.style_manager.push_style({
|
|
'font_size': 16,
|
|
'font_weight': FontWeight.BOLD,
|
|
'font_style': FontStyle.ITALIC,
|
|
'decoration': TextDecoration.UNDERLINE,
|
|
'color': (255, 0, 0),
|
|
'background': (255, 255, 0, 255)
|
|
})
|
|
|
|
font = self.style_manager.create_font()
|
|
|
|
self.assertEqual(font.font_size, 16)
|
|
self.assertEqual(font.weight, FontWeight.BOLD)
|
|
self.assertEqual(font.style, FontStyle.ITALIC)
|
|
self.assertEqual(font.decoration, TextDecoration.UNDERLINE)
|
|
self.assertEqual(font.colour, (255, 0, 0))
|
|
self.assertEqual(font.background, (255, 255, 0, 255))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|