import pytest from promptforge.core.prompt import Prompt, PromptVariable, VariableType from promptforge.core.template import TemplateEngine from promptforge.core.exceptions import MissingVariableError, InvalidPromptError class TestPromptModel: """Tests for Prompt model.""" def test_prompt_creation(self): """Test basic prompt creation.""" prompt = Prompt( name="Test Prompt", content="Hello, {{name}}!", variables=[ PromptVariable(name="name", type=VariableType.STRING, required=True) ] ) assert prompt.name == "Test Prompt" assert len(prompt.variables) == 1 assert prompt.version == "1.0.0" def test_prompt_from_yaml(self, sample_prompt_yaml): """Test parsing prompt from YAML.""" prompt = Prompt.from_yaml(sample_prompt_yaml) assert prompt.name == "Test Prompt" assert prompt.description == "A test prompt for unit testing" assert len(prompt.variables) == 2 assert prompt.variables[0].name == "name" assert prompt.variables[0].required is True def test_prompt_to_yaml(self, sample_prompt_yaml): """Test exporting prompt to YAML.""" prompt = Prompt.from_yaml(sample_prompt_yaml) yaml_str = prompt.to_yaml() assert "---\n" in yaml_str assert "name: Test Prompt" in yaml_str def test_prompt_save_and_load(self, temp_prompts_dir, sample_prompt_yaml): """Test saving and loading prompts.""" prompt = Prompt.from_yaml(sample_prompt_yaml) filepath = prompt.save(temp_prompts_dir) assert filepath.exists() loaded = Prompt.load(filepath) assert loaded.name == prompt.name assert loaded.content == prompt.content def test_prompt_list(self, temp_prompts_dir): """Test listing prompts.""" prompts = Prompt.list(temp_prompts_dir) assert len(prompts) == 0 prompt = Prompt(name="Test1", content="Test") prompt.save(temp_prompts_dir) prompts = Prompt.list(temp_prompts_dir) assert len(prompts) == 1 assert prompts[0].name == "Test1" def test_variable_types(self): """Test different variable types.""" string_var = PromptVariable(name="text", type=VariableType.STRING) int_var = PromptVariable(name="number", type=VariableType.INTEGER) bool_var = PromptVariable(name="flag", type=VariableType.BOOLEAN) choice_var = PromptVariable( name="choice", type=VariableType.CHOICE, choices=["a", "b", "c"] ) assert string_var.type == VariableType.STRING assert int_var.type == VariableType.INTEGER assert bool_var.type == VariableType.BOOLEAN assert choice_var.choices == ["a", "b", "c"] class TestTemplateEngine: """Tests for TemplateEngine.""" def test_get_variables(self): """Test extracting variables from template.""" engine = TemplateEngine() content = "Hello, {{name}}! You have {{count}} items." vars = engine.get_variables(content) assert "name" in vars assert "count" in vars def test_render_basic(self): """Test basic template rendering.""" engine = TemplateEngine() content = "Hello, {{name}}!" result = engine.render(content, {"name": "World"}) assert result == "Hello, World!" def test_render_multiple_vars(self, sample_prompt_content): """Test rendering with multiple variables.""" engine = TemplateEngine() result = engine.render( sample_prompt_content, {"name": "Alice", "count": 5} ) assert result == "Hello, Alice! You have 5 messages." def test_render_missing_required(self): """Test missing required variable raises error.""" engine = TemplateEngine() content = "Hello, {{name}}!" with pytest.raises(Exception): # StrictUndefined raises on missing vars engine.render(content, {}) def test_render_with_defaults(self): """Test rendering with default values.""" engine = TemplateEngine() content = "Hello, {{name}}!" variables = [ PromptVariable(name="name", required=False, default="Guest") ] result = engine.render(content, {}, variables) assert result == "Hello, Guest!" def test_validate_variables_valid(self): """Test variable validation with valid values.""" engine = TemplateEngine() variables = [ PromptVariable(name="name", type=VariableType.STRING, required=True), PromptVariable(name="count", type=VariableType.INTEGER, required=False), ] errors = engine.validate_variables( {"name": "Alice", "count": 5}, variables ) assert len(errors) == 0 def test_validate_variables_missing_required(self): """Test validation fails for missing required variable.""" engine = TemplateEngine() variables = [ PromptVariable(name="name", type=VariableType.STRING, required=True), ] errors = engine.validate_variables({}, variables) assert len(errors) == 1 assert "name" in errors[0] def test_validate_variables_type_error(self): """Test validation fails for wrong type.""" engine = TemplateEngine() variables = [ PromptVariable(name="count", type=VariableType.INTEGER, required=True), ] errors = engine.validate_variables({"count": "not a number"}, variables) assert len(errors) == 1 assert "integer" in errors[0].lower() def test_validate_choices(self): """Test choice validation.""" engine = TemplateEngine() variables = [ PromptVariable( name="color", type=VariableType.CHOICE, required=True, choices=["red", "green", "blue"] ), ] errors = engine.validate_variables({"color": "yellow"}, variables) assert len(errors) == 1 assert "one of" in errors[0].lower() class TestExceptions: """Tests for custom exceptions.""" def test_missing_variable_error(self): """Test MissingVariableError.""" error = MissingVariableError("Missing: name") assert "name" in str(error) def test_invalid_prompt_error(self): """Test InvalidPromptError.""" error = InvalidPromptError("Invalid YAML") assert "YAML" in str(error)