first commit

This commit is contained in:
2025-11-24 23:10:55 -06:00
commit 8315fa51c9
279 changed files with 74600 additions and 0 deletions

View File

@@ -0,0 +1,321 @@
"""
Unit tests for prompt templates module.
"""
import pytest
from pathlib import Path
from app.ai import (
PromptTemplates,
PromptTemplateError,
get_prompt_templates,
render_prompt,
)
class TestPromptTemplates:
"""Tests for PromptTemplates class."""
def setup_method(self):
"""Set up test fixtures."""
self.templates = PromptTemplates()
def test_initialization(self):
"""Test PromptTemplates initializes correctly."""
assert self.templates is not None
assert self.templates.env is not None
def test_template_directory_exists(self):
"""Test that template directory is created."""
assert self.templates.template_dir.exists()
def test_get_template_names(self):
"""Test listing available templates."""
names = self.templates.get_template_names()
assert isinstance(names, list)
# Should have our 4 core templates
assert 'story_action.j2' in names
assert 'combat_action.j2' in names
assert 'quest_offering.j2' in names
assert 'npc_dialogue.j2' in names
def test_render_string_simple(self):
"""Test rendering a simple template string."""
result = self.templates.render_string(
"Hello, {{ name }}!",
name="Player"
)
assert result == "Hello, Player!"
def test_render_string_with_filter(self):
"""Test rendering with custom filter."""
result = self.templates.render_string(
"{{ items | format_inventory }}",
items=[
{"name": "Sword", "quantity": 1},
{"name": "Potion", "quantity": 3}
]
)
assert "Sword" in result
assert "Potion (x3)" in result
def test_render_story_action_template(self):
"""Test rendering story_action template."""
result = self.templates.render(
"story_action.j2",
character={
"name": "Aldric",
"level": 5,
"player_class": "Warrior",
"current_hp": 45,
"max_hp": 50,
"stats": {"strength": 16, "dexterity": 12},
"skills": [],
"effects": []
},
game_state={
"current_location": "The Rusty Anchor",
"location_type": "TAVERN",
"active_quests": [],
"discovered_locations": []
},
action="I look around the tavern for anyone suspicious"
)
assert "Aldric" in result
assert "Warrior" in result
assert "Rusty Anchor" in result
assert "suspicious" in result
def test_render_combat_action_template(self):
"""Test rendering combat_action template."""
result = self.templates.render(
"combat_action.j2",
character={
"name": "Aldric",
"level": 5,
"player_class": "Warrior",
"current_hp": 45,
"max_hp": 50,
"effects": []
},
combat_state={
"round_number": 2,
"current_turn": "Player",
"enemies": [
{
"name": "Goblin",
"current_hp": 8,
"max_hp": 15,
"effects": []
}
]
},
action="swings their sword at the Goblin",
action_result={
"hit": True,
"damage": 7,
"effects_applied": []
},
is_critical=False,
is_finishing_blow=False
)
assert "Aldric" in result
assert "Goblin" in result
assert "sword" in result
def test_render_quest_offering_template(self):
"""Test rendering quest_offering template."""
result = self.templates.render(
"quest_offering.j2",
character={
"name": "Aldric",
"level": 3,
"player_class": "Warrior",
"completed_quests": []
},
game_context={
"current_location": "Village Square",
"location_type": "TOWN",
"active_quests": [],
"world_events": []
},
eligible_quests=[
{
"quest_id": "quest_goblin_cave",
"name": "Clear the Goblin Cave",
"difficulty": "EASY",
"quest_giver": "Village Elder",
"description": "Goblins have been raiding farms",
"narrative_hooks": [
"Farmers complaining about lost livestock"
]
}
],
recent_actions=["Talked to locals"]
)
assert "quest_goblin_cave" in result
assert "Clear the Goblin Cave" in result
assert "Village Elder" in result
def test_render_npc_dialogue_template(self):
"""Test rendering npc_dialogue template."""
result = self.templates.render(
"npc_dialogue.j2",
character={
"name": "Aldric",
"level": 5,
"player_class": "Warrior"
},
npc={
"name": "Grizzled Bartender",
"role": "Tavern Owner",
"personality": "Gruff but kind",
"speaking_style": "Short sentences, common slang"
},
conversation_topic="What's the latest news around here?",
game_state={
"current_location": "The Rusty Anchor",
"time_of_day": "Evening",
"active_quests": []
}
)
assert "Grizzled Bartender" in result
assert "Aldric" in result
assert "news" in result
def test_format_inventory_filter_empty(self):
"""Test format_inventory filter with empty list."""
result = PromptTemplates._format_inventory([])
assert result == "Empty inventory"
def test_format_inventory_filter_single(self):
"""Test format_inventory filter with single item."""
result = PromptTemplates._format_inventory([
{"name": "Sword", "quantity": 1}
])
assert result == "Sword"
def test_format_inventory_filter_multiple(self):
"""Test format_inventory filter with multiple items."""
result = PromptTemplates._format_inventory([
{"name": "Sword", "quantity": 1},
{"name": "Shield", "quantity": 1},
{"name": "Potion", "quantity": 5}
])
assert "Sword" in result
assert "Shield" in result
assert "Potion (x5)" in result
def test_format_inventory_filter_truncation(self):
"""Test format_inventory filter truncates long lists."""
items = [{"name": f"Item{i}", "quantity": 1} for i in range(15)]
result = PromptTemplates._format_inventory(items, max_items=10)
assert "and 5 more items" in result
def test_format_stats_filter(self):
"""Test format_stats filter."""
result = PromptTemplates._format_stats({
"strength": 16,
"dexterity": 14
})
assert "Strength: 16" in result
assert "Dexterity: 14" in result
def test_format_stats_filter_empty(self):
"""Test format_stats filter with empty dict."""
result = PromptTemplates._format_stats({})
assert result == "No stats available"
def test_format_skills_filter(self):
"""Test format_skills filter."""
result = PromptTemplates._format_skills([
{"name": "Sword Mastery", "level": 3},
{"name": "Shield Block", "level": 2}
])
assert "Sword Mastery (Lv.3)" in result
assert "Shield Block (Lv.2)" in result
def test_format_skills_filter_empty(self):
"""Test format_skills filter with empty list."""
result = PromptTemplates._format_skills([])
assert result == "No skills"
def test_format_effects_filter(self):
"""Test format_effects filter."""
result = PromptTemplates._format_effects([
{"name": "Blessed", "remaining_turns": 3},
{"name": "Strength Buff"}
])
assert "Blessed (3 turns)" in result
assert "Strength Buff" in result
def test_format_effects_filter_empty(self):
"""Test format_effects filter with empty list."""
result = PromptTemplates._format_effects([])
assert result == "No active effects"
def test_truncate_text_filter_short(self):
"""Test truncate_text filter with short text."""
result = PromptTemplates._truncate_text("Hello", 100)
assert result == "Hello"
def test_truncate_text_filter_long(self):
"""Test truncate_text filter with long text."""
long_text = "A" * 150
result = PromptTemplates._truncate_text(long_text, 100)
assert len(result) == 100
assert result.endswith("...")
def test_format_gold_filter(self):
"""Test format_gold filter."""
assert PromptTemplates._format_gold(1000) == "1,000 gold"
assert PromptTemplates._format_gold(1000000) == "1,000,000 gold"
assert PromptTemplates._format_gold(50) == "50 gold"
def test_invalid_template_raises_error(self):
"""Test that invalid template raises PromptTemplateError."""
with pytest.raises(PromptTemplateError):
self.templates.render("nonexistent_template.j2")
def test_invalid_template_string_raises_error(self):
"""Test that invalid template string raises PromptTemplateError."""
with pytest.raises(PromptTemplateError):
self.templates.render_string("{{ invalid syntax")
class TestPromptTemplateConvenienceFunctions:
"""Tests for module-level convenience functions."""
def test_get_prompt_templates_singleton(self):
"""Test get_prompt_templates returns singleton."""
templates1 = get_prompt_templates()
templates2 = get_prompt_templates()
assert templates1 is templates2
def test_render_prompt_function(self):
"""Test render_prompt convenience function."""
result = render_prompt(
"story_action.j2",
character={
"name": "Test",
"level": 1,
"player_class": "Warrior",
"current_hp": 10,
"max_hp": 10,
"stats": {},
"skills": [],
"effects": []
},
game_state={
"current_location": "Test Location",
"location_type": "TOWN",
"active_quests": []
},
action="test action"
)
assert "Test" in result
assert "test action" in result