from unittest.mock import patch import pytest from application.templates.template_engine import TemplateEngine, TemplateRenderError @pytest.fixture def engine(): return TemplateEngine() # ── render ───────────────────────────────────────────────────────────────────── @pytest.mark.unit class TestRender: def test_simple_variable(self, engine): result = engine.render("Hello {{ name }}", {"name": "World"}) assert result == "Hello World" def test_empty_template_returns_empty(self, engine): assert engine.render("", {"x": 1}) == "" def test_none_template_returns_empty(self, engine): assert engine.render(None, {"x": 1}) == "" def test_no_variables(self, engine): assert engine.render("plain text", {}) == "plain text" def test_multiple_variables(self, engine): tpl = "{{ a }} and {{ b }}" assert engine.render(tpl, {"a": "X", "b": "Y"}) == "X and Y" def test_nested_dict_access(self, engine): tpl = "{{ data.key }}" assert engine.render(tpl, {"data": {"key": "value"}}) == "value" def test_loop(self, engine): tpl = "{% for i in items %}{{ i }} {% endfor %}" result = engine.render(tpl, {"items": ["a", "b", "c"]}) assert result.strip() == "a b c" def test_conditional(self, engine): tpl = "{% if show %}yes{% else %}no{% endif %}" assert engine.render(tpl, {"show": True}) == "yes" assert engine.render(tpl, {"show": False}) == "no" def test_syntax_error_raises_template_render_error(self, engine): with pytest.raises(TemplateRenderError, match="syntax error"): engine.render("{% if %}", {}) def test_undefined_variable_chainable(self, engine): # ChainableUndefined should NOT raise; it silently returns empty result = engine.render("{{ missing }}", {}) assert result == "" def test_autoescape_html(self, engine): result = engine.render("{{ content }}", {"content": ""}) assert "