""" Test for Issue #65: Template Engine Foundation - Integration Tests This test module validates complete template engine integration scenarios for business document generation, implementing TDD8 Cycle 3. Tests focus on: - Real business document template rendering (invoices, reports) - End-to-end template processing workflows - Performance with realistic data volumes - Integration with MarkdownMatters metadata structure """ import pytest from typing import Dict, Any class TestTemplateEngineIntegration: """Test suite for template engine integration scenarios.""" def setup_method(self): """Set up test environment for each test.""" try: from markitect.template.engine import TemplateEngine self.engine = TemplateEngine() except ImportError: self.engine = None def test_render_complete_invoice_template(self): """Test rendering a complete business invoice template. Reference: Issue #65 - Template Engine Foundation TDD Phase: Integration test for business use case """ # Arrange - Complete invoice template from examples/invoice_template.md invoice_template = """--- title: "Invoice {{invoice_number}}" date: "{{date}}" due_date: "{{due_date}}" customer_id: "{{customer.id}}" --- {{company.name}} {{company.address}} {{company.city}}, {{company.state}} {{company.zip}} {{company.email}} | {{company.phone}} # Invoice {{invoice_number}} **Bill To:** {{customer.name}} {{customer.address}} {{customer.city}}, {{customer.state}} {{customer.zip}} **Invoice Date:** {{date}} **Due Date:** {{due_date}} **Customer ID:** {{customer.id}} ## Summary **Subtotal:** {{subtotal}} **Tax ({{tax_rate}}%):** {{tax_amount}} **Total:** {{total}} {{currency}} ## Payment Information Please remit payment to {{company.name}} within {{payment_terms}} days. --- {{!contentmatter}} invoice_number: "{{invoice_number}}" customer: "{{customer.name}}" total_amount: {{total}} currency: "{{currency}}" status: "generated" {{!/contentmatter}} """ # Test data representing realistic invoice data invoice_data = { "invoice_number": "INV-2025-001", "date": "2025-01-15", "due_date": "2025-02-14", "company": { "name": "MarkiTect Solutions", "address": "123 Business Park", "city": "Tech City", "state": "CA", "zip": "90210", "email": "billing@markitect.com", "phone": "(555) 123-4567" }, "customer": { "id": "CUST-001", "name": "Acme Corporation", "address": "456 Industry Blvd", "city": "Enterprise", "state": "NY", "zip": "10001" }, "subtotal": 1500.00, "tax_rate": 8.5, "tax_amount": 127.50, "total": 1627.50, "currency": "USD", "payment_terms": "30" } # Act & Assert if self.engine is None: pytest.skip("TemplateEngine not implemented yet - TDD integration phase") result = self.engine.render(invoice_template, invoice_data) # Verify critical invoice elements are rendered correctly assert "Invoice INV-2025-001" in result assert "MarkiTect Solutions" in result assert "Acme Corporation" in result assert "123 Business Park" in result assert "Tech City, CA 90210" in result assert "Invoice Date:** 2025-01-15" in result assert "Due Date:** 2025-02-14" in result assert "Customer ID:** CUST-001" in result assert "**Total:** 1627.5 USD" in result assert "Tax (8.5%):** 127.5" in result assert "within 30 days" in result # Verify frontmatter is rendered assert 'title: "Invoice INV-2025-001"' in result assert 'customer_id: "CUST-001"' in result # Verify contentmatter placeholders are rendered assert 'invoice_number: "INV-2025-001"' in result assert 'customer: "Acme Corporation"' in result assert 'total_amount: 1627.5' in result def test_render_business_report_template(self): """Test rendering a business report template with calculations. Reference: Issue #65 - Template Engine Foundation """ # Arrange report_template = """--- title: "{{report_type}} Report - {{period}}" generated: "{{generated_date}}" department: "{{department.name}}" --- # {{report_type}} Report **Period:** {{period}} **Department:** {{department.name}} **Generated:** {{generated_date}} ## Summary - Total Revenue: {{metrics.revenue}} {{currency}} - Total Expenses: {{metrics.expenses}} {{currency}} - Net Profit: {{metrics.profit}} {{currency}} - Profit Margin: {{metrics.profit_margin}}% ## Department Performance **Manager:** {{department.manager}} **Team Size:** {{department.team_size}} **Budget Utilization:** {{department.budget_utilization}}% Contact: {{department.contact.email}} """ report_data = { "report_type": "Monthly Financial", "period": "January 2025", "generated_date": "2025-02-01", "currency": "USD", "department": { "name": "Sales", "manager": "Sarah Johnson", "team_size": 12, "budget_utilization": 85.5, "contact": { "email": "sales@company.com" } }, "metrics": { "revenue": 125000.00, "expenses": 87500.00, "profit": 37500.00, "profit_margin": 30.0 } } # Act & Assert if self.engine is None: pytest.skip("TemplateEngine not implemented yet") result = self.engine.render(report_template, report_data) # Verify report structure and data assert "Monthly Financial Report" in result assert "Period:** January 2025" in result assert "Department:** Sales" in result assert "Total Revenue: 125000.0 USD" in result assert "Net Profit: 37500.0 USD" in result assert "Profit Margin: 30.0%" in result assert "Manager:** Sarah Johnson" in result assert "Budget Utilization:** 85.5%" in result assert "sales@company.com" in result def test_error_handling_missing_nested_data(self): """Test comprehensive error handling with detailed context. Reference: Issue #65 - Template Engine Foundation """ # Arrange template = "Customer: {{customer.profile.details.name}}, Order: {{order.items.first.description}}" incomplete_data = { "customer": { "profile": { # Missing 'details' key } }, "order": { # Missing 'items' key "id": "ORD-001" } } # Act & Assert if self.engine is None: pytest.skip("TemplateEngine not implemented yet") # Test strict mode error with context with pytest.raises(Exception) as exc_info: self.engine.render(template, incomplete_data, strict=True) error_message = str(exc_info.value) # Should provide helpful context about what was available assert ("details" in error_message.lower() or "customer.profile.details.name" in error_message) # Test lenient mode preserves placeholders result = self.engine.render(template, incomplete_data, strict=False) assert "{{customer.profile.details.name}}" in result assert "{{order.items.first.description}}" in result def test_performance_large_business_document(self): """Test performance with realistic large business document. Reference: Issue #65 - Performance Requirements """ # Arrange - Large template with many variables large_template = """# Annual Report {{year}} ## Executive Summary Company: {{company.name}} CEO: {{company.ceo}} Revenue: {{financials.revenue}} {{currency}} ## Department Reports """ # Add many department sections for i in range(50): dept_prefix = f"departments.dept_{i}" large_template += f""" ### Department {{{{{dept_prefix}.name}}}} Manager: {{{{{dept_prefix}.manager}}}} Budget: {{{{{dept_prefix}.budget}}}} {{{{currency}}}} Team Size: {{{{{dept_prefix}.team_size}}}} """ # Generate corresponding data departments_data = {} for i in range(50): departments_data[f"dept_{i}"] = { "name": f"Department {i+1}", "manager": f"Manager {i+1}", "budget": (i+1) * 10000, "team_size": (i % 20) + 5 } large_data = { "year": "2025", "currency": "USD", "company": { "name": "Enterprise Corp", "ceo": "John CEO" }, "financials": { "revenue": 50000000 }, "departments": departments_data } # Act & Assert if self.engine is None: pytest.skip("TemplateEngine not implemented yet") import time start_time = time.time() result = self.engine.render(large_template, large_data) render_time = time.time() - start_time # Performance requirement: <100ms for large documents assert render_time < 0.1 # Verify content was rendered assert "Annual Report 2025" in result assert "Enterprise Corp" in result assert "50000000 USD" in result assert "Department 1" in result assert "Department 50" in result def test_markdown_structure_preservation(self): """Test that complex markdown structure is preserved during rendering. Reference: Issue #65 - Template Engine Foundation """ # Arrange - Complex markdown with various elements complex_template = """--- title: "{{document.title}}" author: "{{document.author}}" --- # {{document.title}} ## Table of Contents - [Introduction](#introduction) - [Analysis](#analysis-{{section.id}}) - [Conclusion](#conclusion) ## Introduction Welcome to **{{document.title}}** by *{{document.author}}*. > This document provides {{description.type}} analysis for {{client.name}}. ### Code Example ```python def process_{{operation.name}}(): return "{{operation.result}}" ``` ## Analysis {{section.id}} | Metric | Value | Target | |--------|-------|--------| | {{metrics.primary.name}} | {{metrics.primary.value}} | {{metrics.primary.target}} | | {{metrics.secondary.name}} | {{metrics.secondary.value}} | {{metrics.secondary.target}} | ### Subsection 1. First point about {{analysis.point1}} 2. Second point about {{analysis.point2}} 3. Third point with [link]({{external.url}}) --- *Generated on {{generation.date}} by {{generation.system}}* """ template_data = { "document": { "title": "Business Analysis Report", "author": "Analytics Team" }, "description": { "type": "comprehensive" }, "client": { "name": "Global Enterprises" }, "section": { "id": "Q1-2025" }, "operation": { "name": "quarterly_analysis", "result": "success" }, "metrics": { "primary": { "name": "Revenue", "value": "$125K", "target": "$120K" }, "secondary": { "name": "Growth", "value": "12%", "target": "10%" } }, "analysis": { "point1": "market expansion", "point2": "customer acquisition" }, "external": { "url": "https://example.com/data" }, "generation": { "date": "2025-01-15", "system": "MarkiTect" } } # Act & Assert if self.engine is None: pytest.skip("TemplateEngine not implemented yet") result = self.engine.render(complex_template, template_data) # Verify markdown structure preservation assert "---" in result # Frontmatter assert "# Business Analysis Report" in result # H1 assert "## Table of Contents" in result # H2 assert "- [Introduction](#introduction)" in result # List assert "> This document provides" in result # Blockquote assert "```python" in result # Code block assert "def process_quarterly_analysis():" in result # Rendered in code assert "| Revenue | $125K | $120K |" in result # Table assert "1. First point about market expansion" in result # Numbered list assert "[link](https://example.com/data)" in result # Link assert "*Generated on 2025-01-15 by MarkiTect*" in result # Emphasis # Verify frontmatter variables were rendered assert 'title: "Business Analysis Report"' in result assert 'author: "Analytics Team"' in result class TestTemplateEngineWorkflows: """Test complete template processing workflows.""" def setup_method(self): """Set up test environment.""" try: from markitect.template.engine import TemplateEngine from markitect.template.parser import TemplateParser self.engine = TemplateEngine() self.parser = TemplateParser() except ImportError: self.engine = None self.parser = None def test_template_validation_workflow(self): """Test complete template validation before rendering workflow. Reference: Issue #65 - Template Engine Foundation """ # Arrange template_with_errors = "Valid: {{name}}, Invalid: {{broken, Incomplete: {missing}" valid_template = "Hello {{name}}, welcome to {{company}}!" test_data = {"name": "Alice", "company": "MarkiTect"} # Act & Assert if self.engine is None or self.parser is None: pytest.skip("Template components not implemented yet") # Test validation of problematic template errors = self.engine.validate_template(template_with_errors) assert len(errors) > 0 # Test validation of good template errors = self.engine.validate_template(valid_template) assert len(errors) == 0 # Test rendering after validation result = self.engine.render(valid_template, test_data) assert result == "Hello Alice, welcome to MarkiTect!" def test_data_completeness_analysis_workflow(self): """Test data completeness analysis before rendering. Reference: Issue #65 - Template Engine Foundation """ # Arrange template = "Invoice {{invoice_number}} for {{customer.name}} - Total: {{total}} {{currency}}" complete_data = { "invoice_number": "INV-001", "customer": {"name": "Acme Corp"}, "total": 1500.00, "currency": "USD" } incomplete_data = { "invoice_number": "INV-001", "customer": {"name": "Acme Corp"} # Missing 'total' and 'currency' } # Act & Assert if self.engine is None: pytest.skip("TemplateEngine not implemented yet") # Test with complete data completeness = self.engine.check_data_completeness(template, complete_data) assert completeness['completeness'] == 1.0 assert len(completeness['missing']) == 0 assert len(completeness['available']) == 4 # Test with incomplete data completeness = self.engine.check_data_completeness(template, incomplete_data) assert completeness['completeness'] < 1.0 assert 'total' in completeness['missing'] assert 'currency' in completeness['missing'] assert 'invoice_number' in completeness['available'] assert 'customer.name' in completeness['available'] if __name__ == '__main__': pytest.main([__file__, '-v'])