"""
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()