From 4113434c7265e6b6c5325d8d0f87dda56cad8505 Mon Sep 17 00:00:00 2001 From: starmen1265 Date: Wed, 11 Mar 2026 13:01:13 +0800 Subject: [PATCH] test(02-03): add failing tests for prompt templates - TestPromptTemplatesExist: 4 tests for template file existence - TestPromptLoader: 6 tests for loading and rendering templates - Tests fail (RED phase) - no templates or loader implemented yet Co-Authored-By: Claude Opus 4.6 --- gsd-openclaw/tests/test_prompt_templates.py | 123 ++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 gsd-openclaw/tests/test_prompt_templates.py diff --git a/gsd-openclaw/tests/test_prompt_templates.py b/gsd-openclaw/tests/test_prompt_templates.py new file mode 100644 index 0000000..acf1375 --- /dev/null +++ b/gsd-openclaw/tests/test_prompt_templates.py @@ -0,0 +1,123 @@ +""" +Tests for prompt templates and PromptLoader module. +Task 1: Test prompt template files exist with variable placeholders. +Task 2: Test PromptLoader loads and renders templates correctly. +""" +import pytest +from pathlib import Path + +# Path to prompts directory +PROMPTS_DIR = Path(__file__).parent.parent / "src" / "gsd_openclaw" / "prompts" + + +class TestPromptTemplatesExist: + """Test that prompt template files exist and contain variable placeholders.""" + + def test_context_recovery_template_exists(self): + """context_recovery.md template exists.""" + template_path = PROMPTS_DIR / "context_recovery.md" + assert template_path.exists(), f"Template not found: {template_path}" + + def test_command_mapping_template_exists(self): + """command_mapping.md template exists.""" + template_path = PROMPTS_DIR / "command_mapping.md" + assert template_path.exists(), f"Template not found: {template_path}" + + def test_error_recovery_template_exists(self): + """error_recovery.md template exists.""" + template_path = PROMPTS_DIR / "error_recovery.md" + assert template_path.exists(), f"Template not found: {template_path}" + + def test_templates_contain_variable_placeholders(self): + """All templates contain {{variable}} placeholders.""" + template_files = [ + PROMPTS_DIR / "context_recovery.md", + PROMPTS_DIR / "command_mapping.md", + PROMPTS_DIR / "error_recovery.md", + ] + for template_path in template_files: + content = template_path.read_text(encoding='utf-8') + # Check for at least one {{variable}} pattern + assert "{{" in content and "}}" in content, \ + f"Template {template_path.name} has no {{variable}} placeholders" + + +class TestPromptLoader: + """Test PromptLoader class for loading and rendering templates.""" + + def test_render_substitutes_variables(self): + """PromptLoader.render substitutes variables correctly.""" + from gsd_openclaw.prompt_loader import PromptLoader + + loader = PromptLoader(PROMPTS_DIR) + result = loader.render( + "context_recovery", + project_name="test-project", + last_active_at="2026-03-11", + current_phase="Phase 1", + command_count="5", + last_output_snapshot="Last output" + ) + + assert "test-project" in result + assert "{{project_name}}" not in result + + def test_render_handles_missing_variables(self): + """PromptLoader.render leaves missing variables as literal {{variable}}.""" + from gsd_openclaw.prompt_loader import PromptLoader + + loader = PromptLoader(PROMPTS_DIR) + # Render with only partial variables - missing ones should remain as {{var}} + result = loader.render( + "context_recovery", + project_name="test-project" + # Missing: last_active_at, current_phase, etc. + ) + + # Should have substituted project_name + assert "test-project" in result + # Missing variables should remain as {{variable}} + assert "{{last_active_at}}" in result or "{{current_phase}}" in result + + def test_render_raises_for_missing_template(self): + """PromptLoader.render raises FileNotFoundError for missing template.""" + from gsd_openclaw.prompt_loader import PromptLoader + + loader = PromptLoader(PROMPTS_DIR) + + with pytest.raises(FileNotFoundError, match="Template not found"): + loader.render("nonexistent_template") + + def test_get_returns_raw_template_content(self): + """PromptLoader.get returns raw template content (cached).""" + from gsd_openclaw.prompt_loader import PromptLoader + + loader = PromptLoader(PROMPTS_DIR) + content = loader.get("context_recovery") + + assert isinstance(content, str) + assert "{{project_name}}" in content + assert len(content) > 0 + + def test_get_caches_template(self): + """PromptLoader caches templates after first load.""" + from gsd_openclaw.prompt_loader import PromptLoader + + loader = PromptLoader(PROMPTS_DIR) + + # First load + content1 = loader.get("context_recovery") + # Second load (should be from cache) + content2 = loader.get("context_recovery") + + # Should be the same object (cached) + assert content1 == content2 + assert "context_recovery" in loader._cache + + def test_default_template_dir(self): + """PromptLoader uses default prompts directory when none specified.""" + from gsd_openclaw.prompt_loader import PromptLoader + + loader = PromptLoader() + expected_dir = Path(__file__).parent.parent / "src" / "gsd_openclaw" / "prompts" + assert loader.template_dir == expected_dir