""" Tests for engine.render module. """ from unittest.mock import MagicMock, patch import pytest from engine.legacy.render import ( GRAD_COLS, MSG_GRAD_COLS, clear_font_cache, font_for_lang, lr_gradient, lr_gradient_opposite, make_block, ) class TestGradientConstants: """Tests for gradient color constants.""" def test_grad_cols_defined(self): """GRAD_COLS is defined with expected length.""" assert len(GRAD_COLS) > 0 assert all(isinstance(c, str) for c in GRAD_COLS) def test_msg_grad_cols_defined(self): """MSG_GRAD_COLS is defined with expected length.""" assert len(MSG_GRAD_COLS) > 0 assert all(isinstance(c, str) for c in MSG_GRAD_COLS) def test_grad_cols_start_with_white(self): """GRAD_COLS starts with white.""" assert "231" in GRAD_COLS[0] def test_msg_grad_cols_different_from_grad_cols(self): """MSG_GRAD_COLS is different from GRAD_COLS.""" assert MSG_GRAD_COLS != GRAD_COLS class TestLrGradient: """Tests for lr_gradient function.""" def test_empty_rows(self): """Empty input returns empty output.""" result = lr_gradient([], 0.0) assert result == [] def test_preserves_empty_rows(self): """Empty rows are preserved.""" result = lr_gradient([""], 0.0) assert result == [""] def test_adds_gradient_to_content(self): """Non-empty rows get gradient coloring.""" result = lr_gradient(["hello"], 0.0) assert len(result) == 1 assert "\033[" in result[0] def test_preserves_spaces(self): """Spaces are preserved without coloring.""" result = lr_gradient(["hello world"], 0.0) assert " " in result[0] def test_offset_wraps_around(self): """Offset wraps around at 1.0.""" result1 = lr_gradient(["hello"], 0.0) result2 = lr_gradient(["hello"], 1.0) assert result1 != result2 or result1 == result2 class TestLrGradientOpposite: """Tests for lr_gradient_opposite function.""" def test_uses_msg_grad_cols(self): """Uses MSG_GRAD_COLS instead of GRAD_COLS.""" result = lr_gradient_opposite(["test"]) assert "\033[" in result[0] class TestClearFontCache: """Tests for clear_font_cache function.""" def test_clears_without_error(self): """Function runs without error.""" clear_font_cache() class TestFontForLang: """Tests for font_for_lang function.""" @patch("engine.render.font") def test_returns_default_for_none(self, mock_font): """Returns default font when lang is None.""" result = font_for_lang(None) assert result is not None @patch("engine.render.font") def test_returns_default_for_unknown_lang(self, mock_font): """Returns default font for unknown language.""" result = font_for_lang("unknown_lang") assert result is not None class TestMakeBlock: """Tests for make_block function.""" @patch("engine.translate.translate_headline") @patch("engine.translate.detect_location_language") @patch("engine.render.font_for_lang") @patch("engine.render.big_wrap") @patch("engine.render.random") def test_make_block_basic( self, mock_random, mock_wrap, mock_font, mock_detect, mock_translate ): """Basic make_block returns content, color, meta index.""" mock_wrap.return_value = ["Headline content", ""] mock_random.choice.return_value = "\033[38;5;46m" content, color, meta_idx = make_block( "Test headline", "TestSource", "12:00", 80 ) assert len(content) > 0 assert color is not None assert meta_idx >= 0 @pytest.mark.skip(reason="Requires full PIL/font environment") @patch("engine.translate.translate_headline") @patch("engine.translate.detect_location_language") @patch("engine.render.font_for_lang") @patch("engine.render.big_wrap") @patch("engine.render.random") def test_make_block_translation( self, mock_random, mock_wrap, mock_font, mock_detect, mock_translate ): """Translation is applied when mode is news.""" mock_wrap.return_value = ["Translated"] mock_random.choice.return_value = "\033[38;5;46m" mock_detect.return_value = "de" with patch("engine.config.MODE", "news"): content, _, _ = make_block("Test", "Source", "12:00", 80) mock_translate.assert_called_once() @patch("engine.translate.translate_headline") @patch("engine.translate.detect_location_language") @patch("engine.render.font_for_lang") @patch("engine.render.big_wrap") @patch("engine.render.random") def test_make_block_no_translation_poetry( self, mock_random, mock_wrap, mock_font, mock_detect, mock_translate ): """No translation when mode is poetry.""" mock_wrap.return_value = ["Poem content"] mock_random.choice.return_value = "\033[38;5;46m" with patch("engine.config.MODE", "poetry"): make_block("Test", "Source", "12:00", 80) mock_translate.assert_not_called() @patch("engine.translate.translate_headline") @patch("engine.translate.detect_location_language") @patch("engine.render.font_for_lang") @patch("engine.render.big_wrap") @patch("engine.render.random") def test_make_block_meta_format( self, mock_random, mock_wrap, mock_font, mock_detect, mock_translate ): """Meta line includes source and timestamp.""" mock_wrap.return_value = ["Content"] mock_random.choice.return_value = "\033[38;5;46m" content, _, meta_idx = make_block("Test", "MySource", "14:30", 80) meta_line = content[meta_idx] assert "MySource" in meta_line assert "14:30" in meta_line class TestRenderLine: """Tests for render_line function.""" def test_empty_string(self): """Empty string returns empty list.""" from engine.legacy.render import render_line result = render_line("") assert result == [""] @pytest.mark.skip(reason="Requires real font/PIL setup") def test_uses_default_font(self): """Uses default font when none provided.""" from engine.legacy.render import render_line with patch("engine.render.font") as mock_font: mock_font.return_value = MagicMock() mock_font.return_value.getbbox.return_value = (0, 0, 10, 10) render_line("test") def test_getbbox_returns_none(self): """Handles None bbox gracefully.""" from engine.legacy.render import render_line with patch("engine.render.font") as mock_font: mock_font.return_value = MagicMock() mock_font.return_value.getbbox.return_value = None result = render_line("test") assert result == [""] class TestBigWrap: """Tests for big_wrap function.""" def test_empty_string(self): """Empty string returns empty list.""" from engine.legacy.render import big_wrap result = big_wrap("", 80) assert result == [] @pytest.mark.skip(reason="Requires real font/PIL setup") def test_single_word_fits(self): """Single short word returns rendered.""" from engine.legacy.render import big_wrap with patch("engine.render.font") as mock_font: mock_font.return_value = MagicMock() mock_font.return_value.getbbox.return_value = (0, 0, 10, 10) result = big_wrap("test", 80) assert len(result) > 0