"""Unit tests for template models.""" import pytest from markitect.prompts.templates.models import ( ContentMacro, MacroKind, PromptTemplate, TemplateMetadata, ) from markitect.prompts.models import ArtifactType class TestContentMacro: """Tests for ContentMacro.""" def test_create_required_macro(self): """Test creating required macro.""" macro = ContentMacro( kind=MacroKind.REQUIRED, target="glossary", ) assert macro.kind == MacroKind.REQUIRED assert macro.target == "glossary" assert macro.parameters == {} def test_create_macro_with_parameters(self): """Test creating macro with parameters.""" macro = ContentMacro( kind=MacroKind.GENERATE, target="code-examples", parameters={"language": "python", "framework": "fastapi"}, ) assert macro.parameters == {"language": "python", "framework": "fastapi"} def test_macro_str_representation(self): """Test string representation.""" macro = ContentMacro( kind=MacroKind.REQUIRED, target="test", ) assert str(macro) == "{{required:test}}" def test_macro_str_with_parameters(self): """Test string representation with parameters.""" macro = ContentMacro( kind=MacroKind.GENERATE, target="gen", parameters={"key": "value"}, ) assert "generate:gen" in str(macro) assert "key=value" in str(macro) def test_macro_to_dict(self): """Test serialization to dict.""" macro = ContentMacro( kind=MacroKind.OPTIONAL, target="test", parameters={"a": "1"}, raw_text="{{optional:test|a=1}}", line_number=42, ) data = macro.to_dict() assert data["kind"] == "optional" assert data["target"] == "test" assert data["parameters"] == {"a": "1"} assert data["line_number"] == 42 def test_macro_from_dict(self): """Test deserialization from dict.""" data = { "kind": "required", "target": "test", "parameters": {"x": "y"}, "raw_text": "{{require:test|x=y}}", "line_number": 10, } macro = ContentMacro.from_dict(data) assert macro.kind == MacroKind.REQUIRED assert macro.target == "test" assert macro.parameters == {"x": "y"} assert macro.line_number == 10 class TestTemplateMetadata: """Tests for TemplateMetadata.""" def test_create_empty_metadata(self): """Test creating empty metadata.""" meta = TemplateMetadata() assert meta.purpose is None assert meta.model_hints == {} assert meta.expected_inputs == [] assert meta.output_type is None def test_create_metadata_with_values(self): """Test creating metadata with values.""" meta = TemplateMetadata( purpose="Generate API docs", model_hints={"temperature": 0.7}, expected_inputs=["api-spec", "examples"], output_type="markdown", ) assert meta.purpose == "Generate API docs" assert meta.model_hints == {"temperature": 0.7} assert meta.expected_inputs == ["api-spec", "examples"] assert meta.output_type == "markdown" def test_metadata_to_dict(self): """Test serialization.""" meta = TemplateMetadata(purpose="Test") data = meta.to_dict() assert data["purpose"] == "Test" assert "model_hints" in data def test_metadata_from_dict(self): """Test deserialization.""" data = { "purpose": "Test", "model_hints": {"temp": 0.5}, "expected_inputs": ["in1"], "output_type": "json", } meta = TemplateMetadata.from_dict(data) assert meta.purpose == "Test" assert meta.model_hints == {"temp": 0.5} class TestPromptTemplate: """Tests for PromptTemplate.""" def test_create_template(self): """Test template creation.""" template = PromptTemplate.create( space_id="space-1", name="test-template", content="# Template\n{{require:glossary}}", ) assert template.space_id == "space-1" assert template.name == "test-template" assert template.artifact.artifact_type == ArtifactType.TEMPLATE assert not template.analyzed assert template.macros == [] def test_template_properties(self): """Test template properties.""" template = PromptTemplate.create( space_id="space-1", name="test", content="content", ) assert template.id # Has UUID assert template.space_id == "space-1" assert template.name == "test" assert template.content_digest # Has digest def test_get_required_dependencies(self): """Test extracting required dependencies.""" template = PromptTemplate.create( space_id="space-1", name="test", content="content", ) template.macros = [ ContentMacro(kind=MacroKind.REQUIRED, target="dep1"), ContentMacro(kind=MacroKind.OPTIONAL, target="dep2"), ContentMacro(kind=MacroKind.REQUIRED, target="dep3"), ] required = template.get_required_dependencies() assert required == ["dep1", "dep3"] def test_get_optional_dependencies(self): """Test extracting optional dependencies.""" template = PromptTemplate.create( space_id="space-1", name="test", content="content", ) template.macros = [ ContentMacro(kind=MacroKind.REQUIRED, target="dep1"), ContentMacro(kind=MacroKind.OPTIONAL, target="dep2"), ContentMacro(kind=MacroKind.OPTIONAL, target="dep3"), ] optional = template.get_optional_dependencies() assert optional == ["dep2", "dep3"] def test_get_generators(self): """Test extracting generators.""" template = PromptTemplate.create( space_id="space-1", name="test", content="content", ) template.macros = [ ContentMacro(kind=MacroKind.GENERATE, target="gen1"), ContentMacro(kind=MacroKind.REQUIRED, target="dep1"), ContentMacro(kind=MacroKind.GENERATE, target="gen2"), ] generators = template.get_generators() assert generators == ["gen1", "gen2"] def test_from_artifact_invalid_type(self): """Test from_artifact raises error for non-template.""" from markitect.prompts.models import Artifact artifact = Artifact.create( space_id="space-1", name="not-template", content="content", artifact_type=ArtifactType.CONTENT, ) with pytest.raises(ValueError, match="must be of type TEMPLATE"): PromptTemplate.from_artifact(artifact) def test_template_to_dict(self): """Test serialization.""" template = PromptTemplate.create( space_id="space-1", name="test", content="content", ) template.analyzed = True data = template.to_dict() assert "artifact" in data assert "template_metadata" in data assert data["analyzed"] is True def test_template_from_dict(self): """Test deserialization.""" original = PromptTemplate.create( space_id="space-1", name="test", content="content", ) data = original.to_dict() restored = PromptTemplate.from_dict(data) assert restored.id == original.id assert restored.name == original.name