This commit is contained in:
Pablo Estevez
2026-01-17 17:29:21 +00:00
parent c89f059712
commit 5ed767ff9a
144 changed files with 14142 additions and 16488 deletions

View File

@@ -11,16 +11,11 @@ Tests dual-mode AI enhancement for how-to guides:
import json
import os
import pytest
from unittest.mock import Mock, patch, MagicMock
from pathlib import Path
from unittest.mock import MagicMock, Mock, patch
from skill_seekers.cli.guide_enhancer import (
GuideEnhancer,
PrerequisiteItem,
TroubleshootingItem,
StepEnhancement
)
import pytest
from skill_seekers.cli.guide_enhancer import GuideEnhancer, PrerequisiteItem, StepEnhancement, TroubleshootingItem
class TestGuideEnhancerModeDetection:
@@ -28,43 +23,43 @@ class TestGuideEnhancerModeDetection:
def test_auto_mode_with_api_key(self):
"""Test auto mode detects API when key present and library available"""
with patch.dict(os.environ, {'ANTHROPIC_API_KEY': 'sk-ant-test'}):
with patch('skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE', True):
with patch('skill_seekers.cli.guide_enhancer.anthropic', create=True) as mock_anthropic:
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch("skill_seekers.cli.guide_enhancer.anthropic", create=True) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode='auto')
enhancer = GuideEnhancer(mode="auto")
# Will be 'api' if library available, otherwise 'local' or 'none'
assert enhancer.mode in ['api', 'local', 'none']
assert enhancer.mode in ["api", "local", "none"]
def test_auto_mode_without_api_key(self):
"""Test auto mode falls back to LOCAL when no API key"""
with patch.dict(os.environ, {}, clear=True):
if 'ANTHROPIC_API_KEY' in os.environ:
del os.environ['ANTHROPIC_API_KEY']
if "ANTHROPIC_API_KEY" in os.environ:
del os.environ["ANTHROPIC_API_KEY"]
enhancer = GuideEnhancer(mode='auto')
assert enhancer.mode in ['local', 'none']
enhancer = GuideEnhancer(mode="auto")
assert enhancer.mode in ["local", "none"]
def test_explicit_api_mode(self):
"""Test explicit API mode"""
enhancer = GuideEnhancer(mode='api')
assert enhancer.mode in ['api', 'none'] # none if no API key
enhancer = GuideEnhancer(mode="api")
assert enhancer.mode in ["api", "none"] # none if no API key
def test_explicit_local_mode(self):
"""Test explicit LOCAL mode"""
enhancer = GuideEnhancer(mode='local')
assert enhancer.mode in ['local', 'none'] # none if no claude CLI
enhancer = GuideEnhancer(mode="local")
assert enhancer.mode in ["local", "none"] # none if no claude CLI
def test_explicit_none_mode(self):
"""Test explicit none mode"""
enhancer = GuideEnhancer(mode='none')
assert enhancer.mode == 'none'
enhancer = GuideEnhancer(mode="none")
assert enhancer.mode == "none"
def test_claude_cli_check(self):
"""Test Claude CLI availability check"""
enhancer = GuideEnhancer(mode='local')
enhancer = GuideEnhancer(mode="local")
# Should either detect claude or fall back to api/none
assert enhancer.mode in ['local', 'api', 'none']
assert enhancer.mode in ["local", "api", "none"]
class TestGuideEnhancerStepDescriptions:
@@ -72,58 +67,58 @@ class TestGuideEnhancerStepDescriptions:
def test_enhance_step_descriptions_empty_list(self):
"""Test with empty steps list"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
steps = []
result = enhancer.enhance_step_descriptions(steps)
assert result == []
def test_enhance_step_descriptions_none_mode(self):
"""Test step descriptions in none mode returns empty"""
enhancer = GuideEnhancer(mode='none')
steps = [
{'description': 'scraper.scrape(url)', 'code': 'result = scraper.scrape(url)'}
]
enhancer = GuideEnhancer(mode="none")
steps = [{"description": "scraper.scrape(url)", "code": "result = scraper.scrape(url)"}]
result = enhancer.enhance_step_descriptions(steps)
assert result == []
@patch.object(GuideEnhancer, '_call_claude_api')
@patch.object(GuideEnhancer, "_call_claude_api")
def test_enhance_step_descriptions_api_mode(self, mock_call):
"""Test step descriptions with API mode"""
mock_call.return_value = json.dumps({
'step_descriptions': [
{
'step_index': 0,
'explanation': 'Initialize the scraper with the target URL',
'variations': ['Use async scraper for better performance']
}
]
})
mock_call.return_value = json.dumps(
{
"step_descriptions": [
{
"step_index": 0,
"explanation": "Initialize the scraper with the target URL",
"variations": ["Use async scraper for better performance"],
}
]
}
)
with patch.dict(os.environ, {'ANTHROPIC_API_KEY': 'sk-ant-test'}):
with patch('skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE', True):
with patch('skill_seekers.cli.guide_enhancer.anthropic', create=True) as mock_anthropic:
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch("skill_seekers.cli.guide_enhancer.anthropic", create=True) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode='api')
if enhancer.mode != 'api':
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock() # Mock the client
steps = [{'description': 'scraper.scrape(url)', 'code': 'result = scraper.scrape(url)'}]
steps = [{"description": "scraper.scrape(url)", "code": "result = scraper.scrape(url)"}]
result = enhancer.enhance_step_descriptions(steps)
assert len(result) == 1
assert isinstance(result[0], StepEnhancement)
assert result[0].step_index == 0
assert 'Initialize' in result[0].explanation
assert "Initialize" in result[0].explanation
assert len(result[0].variations) == 1
def test_enhance_step_descriptions_malformed_json(self):
"""Test handling of malformed JSON response"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
with patch.object(enhancer, '_call_ai', return_value='invalid json'):
steps = [{'description': 'test', 'code': 'code'}]
with patch.object(enhancer, "_call_ai", return_value="invalid json"):
steps = [{"description": "test", "code": "code"}]
result = enhancer.enhance_step_descriptions(steps)
assert result == []
@@ -133,52 +128,50 @@ class TestGuideEnhancerTroubleshooting:
def test_enhance_troubleshooting_none_mode(self):
"""Test troubleshooting in none mode"""
enhancer = GuideEnhancer(mode='none')
guide_data = {
'title': 'Test Guide',
'steps': [{'description': 'test', 'code': 'code'}],
'language': 'python'
}
enhancer = GuideEnhancer(mode="none")
guide_data = {"title": "Test Guide", "steps": [{"description": "test", "code": "code"}], "language": "python"}
result = enhancer.enhance_troubleshooting(guide_data)
assert result == []
@patch.object(GuideEnhancer, '_call_claude_api')
@patch.object(GuideEnhancer, "_call_claude_api")
def test_enhance_troubleshooting_api_mode(self, mock_call):
"""Test troubleshooting with API mode"""
mock_call.return_value = json.dumps({
'troubleshooting': [
{
'problem': 'ImportError: No module named requests',
'symptoms': ['Import fails', 'Module not found error'],
'diagnostic_steps': ['Check pip list', 'Verify virtual env'],
'solution': 'Run: pip install requests'
}
]
})
mock_call.return_value = json.dumps(
{
"troubleshooting": [
{
"problem": "ImportError: No module named requests",
"symptoms": ["Import fails", "Module not found error"],
"diagnostic_steps": ["Check pip list", "Verify virtual env"],
"solution": "Run: pip install requests",
}
]
}
)
with patch.dict(os.environ, {'ANTHROPIC_API_KEY': 'sk-ant-test'}):
with patch('skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE', True):
with patch('skill_seekers.cli.guide_enhancer.anthropic', create=True) as mock_anthropic:
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch("skill_seekers.cli.guide_enhancer.anthropic", create=True) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode='api')
if enhancer.mode != 'api':
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
guide_data = {
'title': 'Test Guide',
'steps': [{'description': 'import requests', 'code': 'import requests'}],
'language': 'python'
"title": "Test Guide",
"steps": [{"description": "import requests", "code": "import requests"}],
"language": "python",
}
result = enhancer.enhance_troubleshooting(guide_data)
assert len(result) == 1
assert isinstance(result[0], TroubleshootingItem)
assert 'ImportError' in result[0].problem
assert "ImportError" in result[0].problem
assert len(result[0].symptoms) == 2
assert len(result[0].diagnostic_steps) == 2
assert 'pip install' in result[0].solution
assert "pip install" in result[0].solution
class TestGuideEnhancerPrerequisites:
@@ -186,53 +179,51 @@ class TestGuideEnhancerPrerequisites:
def test_enhance_prerequisites_empty_list(self):
"""Test with empty prerequisites"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
result = enhancer.enhance_prerequisites([])
assert result == []
def test_enhance_prerequisites_none_mode(self):
"""Test prerequisites in none mode"""
enhancer = GuideEnhancer(mode='none')
prereqs = ['requests', 'beautifulsoup4']
enhancer = GuideEnhancer(mode="none")
prereqs = ["requests", "beautifulsoup4"]
result = enhancer.enhance_prerequisites(prereqs)
assert result == []
@patch.object(GuideEnhancer, '_call_claude_api')
@patch.object(GuideEnhancer, "_call_claude_api")
def test_enhance_prerequisites_api_mode(self, mock_call):
"""Test prerequisites with API mode"""
mock_call.return_value = json.dumps({
'prerequisites_detailed': [
{
'name': 'requests',
'why': 'HTTP client for making web requests',
'setup': 'pip install requests'
},
{
'name': 'beautifulsoup4',
'why': 'HTML/XML parser for web scraping',
'setup': 'pip install beautifulsoup4'
}
]
})
mock_call.return_value = json.dumps(
{
"prerequisites_detailed": [
{"name": "requests", "why": "HTTP client for making web requests", "setup": "pip install requests"},
{
"name": "beautifulsoup4",
"why": "HTML/XML parser for web scraping",
"setup": "pip install beautifulsoup4",
},
]
}
)
with patch.dict(os.environ, {'ANTHROPIC_API_KEY': 'sk-ant-test'}):
with patch('skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE', True):
with patch('skill_seekers.cli.guide_enhancer.anthropic', create=True) as mock_anthropic:
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch("skill_seekers.cli.guide_enhancer.anthropic", create=True) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode='api')
if enhancer.mode != 'api':
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
prereqs = ['requests', 'beautifulsoup4']
prereqs = ["requests", "beautifulsoup4"]
result = enhancer.enhance_prerequisites(prereqs)
assert len(result) == 2
assert isinstance(result[0], PrerequisiteItem)
assert result[0].name == 'requests'
assert 'HTTP client' in result[0].why
assert 'pip install' in result[0].setup
assert result[0].name == "requests"
assert "HTTP client" in result[0].why
assert "pip install" in result[0].setup
class TestGuideEnhancerNextSteps:
@@ -240,38 +231,34 @@ class TestGuideEnhancerNextSteps:
def test_enhance_next_steps_none_mode(self):
"""Test next steps in none mode"""
enhancer = GuideEnhancer(mode='none')
guide_data = {'title': 'Test Guide', 'description': 'Test'}
enhancer = GuideEnhancer(mode="none")
guide_data = {"title": "Test Guide", "description": "Test"}
result = enhancer.enhance_next_steps(guide_data)
assert result == []
@patch.object(GuideEnhancer, '_call_claude_api')
@patch.object(GuideEnhancer, "_call_claude_api")
def test_enhance_next_steps_api_mode(self, mock_call):
"""Test next steps with API mode"""
mock_call.return_value = json.dumps({
'next_steps': [
'How to handle async workflows',
'How to add error handling',
'How to implement caching'
]
})
mock_call.return_value = json.dumps(
{"next_steps": ["How to handle async workflows", "How to add error handling", "How to implement caching"]}
)
with patch.dict(os.environ, {'ANTHROPIC_API_KEY': 'sk-ant-test'}):
with patch('skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE', True):
with patch('skill_seekers.cli.guide_enhancer.anthropic', create=True) as mock_anthropic:
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch("skill_seekers.cli.guide_enhancer.anthropic", create=True) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode='api')
if enhancer.mode != 'api':
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
guide_data = {'title': 'How to Scrape Docs', 'description': 'Basic scraping'}
guide_data = {"title": "How to Scrape Docs", "description": "Basic scraping"}
result = enhancer.enhance_next_steps(guide_data)
assert len(result) == 3
assert 'async' in result[0].lower()
assert 'error' in result[1].lower()
assert "async" in result[0].lower()
assert "error" in result[1].lower()
class TestGuideEnhancerUseCases:
@@ -279,37 +266,39 @@ class TestGuideEnhancerUseCases:
def test_enhance_use_cases_none_mode(self):
"""Test use cases in none mode"""
enhancer = GuideEnhancer(mode='none')
guide_data = {'title': 'Test Guide', 'description': 'Test'}
enhancer = GuideEnhancer(mode="none")
guide_data = {"title": "Test Guide", "description": "Test"}
result = enhancer.enhance_use_cases(guide_data)
assert result == []
@patch.object(GuideEnhancer, '_call_claude_api')
@patch.object(GuideEnhancer, "_call_claude_api")
def test_enhance_use_cases_api_mode(self, mock_call):
"""Test use cases with API mode"""
mock_call.return_value = json.dumps({
'use_cases': [
'Use when you need to automate documentation extraction',
'Ideal for building knowledge bases from technical docs'
]
})
mock_call.return_value = json.dumps(
{
"use_cases": [
"Use when you need to automate documentation extraction",
"Ideal for building knowledge bases from technical docs",
]
}
)
with patch.dict(os.environ, {'ANTHROPIC_API_KEY': 'sk-ant-test'}):
with patch('skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE', True):
with patch('skill_seekers.cli.guide_enhancer.anthropic', create=True) as mock_anthropic:
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch("skill_seekers.cli.guide_enhancer.anthropic", create=True) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode='api')
if enhancer.mode != 'api':
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
guide_data = {'title': 'How to Scrape Docs', 'description': 'Documentation scraping'}
guide_data = {"title": "How to Scrape Docs", "description": "Documentation scraping"}
result = enhancer.enhance_use_cases(guide_data)
assert len(result) == 2
assert 'automate' in result[0].lower()
assert 'knowledge base' in result[1].lower()
assert "automate" in result[0].lower()
assert "knowledge base" in result[1].lower()
class TestGuideEnhancerFullWorkflow:
@@ -317,97 +306,97 @@ class TestGuideEnhancerFullWorkflow:
def test_enhance_guide_none_mode(self):
"""Test full guide enhancement in none mode"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
guide_data = {
'title': 'How to Scrape Documentation',
'steps': [
{'description': 'Import libraries', 'code': 'import requests'},
{'description': 'Create scraper', 'code': 'scraper = Scraper()'}
"title": "How to Scrape Documentation",
"steps": [
{"description": "Import libraries", "code": "import requests"},
{"description": "Create scraper", "code": "scraper = Scraper()"},
],
'language': 'python',
'prerequisites': ['requests'],
'description': 'Basic scraping guide'
"language": "python",
"prerequisites": ["requests"],
"description": "Basic scraping guide",
}
result = enhancer.enhance_guide(guide_data)
# In none mode, should return original guide
assert result['title'] == guide_data['title']
assert len(result['steps']) == 2
assert result["title"] == guide_data["title"]
assert len(result["steps"]) == 2
@patch.object(GuideEnhancer, '_call_claude_api')
@patch.object(GuideEnhancer, "_call_claude_api")
def test_enhance_guide_api_mode_success(self, mock_call):
"""Test successful full guide enhancement via API"""
mock_call.return_value = json.dumps({
'step_descriptions': [
{'step_index': 0, 'explanation': 'Import required libraries', 'variations': []},
{'step_index': 1, 'explanation': 'Initialize scraper instance', 'variations': []}
],
'troubleshooting': [
{
'problem': 'Import error',
'symptoms': ['Module not found'],
'diagnostic_steps': ['Check installation'],
'solution': 'pip install requests'
}
],
'prerequisites_detailed': [
{'name': 'requests', 'why': 'HTTP client', 'setup': 'pip install requests'}
],
'next_steps': ['How to add authentication'],
'use_cases': ['Automate documentation extraction']
})
mock_call.return_value = json.dumps(
{
"step_descriptions": [
{"step_index": 0, "explanation": "Import required libraries", "variations": []},
{"step_index": 1, "explanation": "Initialize scraper instance", "variations": []},
],
"troubleshooting": [
{
"problem": "Import error",
"symptoms": ["Module not found"],
"diagnostic_steps": ["Check installation"],
"solution": "pip install requests",
}
],
"prerequisites_detailed": [{"name": "requests", "why": "HTTP client", "setup": "pip install requests"}],
"next_steps": ["How to add authentication"],
"use_cases": ["Automate documentation extraction"],
}
)
with patch.dict(os.environ, {'ANTHROPIC_API_KEY': 'sk-ant-test'}):
with patch('skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE', True):
with patch('skill_seekers.cli.guide_enhancer.anthropic', create=True) as mock_anthropic:
with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-ant-test"}):
with patch("skill_seekers.cli.guide_enhancer.ANTHROPIC_AVAILABLE", True):
with patch("skill_seekers.cli.guide_enhancer.anthropic", create=True) as mock_anthropic:
mock_anthropic.Anthropic = Mock()
enhancer = GuideEnhancer(mode='api')
if enhancer.mode != 'api':
enhancer = GuideEnhancer(mode="api")
if enhancer.mode != "api":
pytest.skip("API mode not available")
enhancer.client = Mock()
guide_data = {
'title': 'How to Scrape Documentation',
'steps': [
{'description': 'Import libraries', 'code': 'import requests'},
{'description': 'Create scraper', 'code': 'scraper = Scraper()'}
"title": "How to Scrape Documentation",
"steps": [
{"description": "Import libraries", "code": "import requests"},
{"description": "Create scraper", "code": "scraper = Scraper()"},
],
'language': 'python',
'prerequisites': ['requests'],
'description': 'Basic scraping guide'
"language": "python",
"prerequisites": ["requests"],
"description": "Basic scraping guide",
}
result = enhancer.enhance_guide(guide_data)
# Check enhancements were applied
assert 'step_enhancements' in result
assert 'troubleshooting_detailed' in result
assert 'prerequisites_detailed' in result
assert 'next_steps_detailed' in result
assert 'use_cases' in result
assert "step_enhancements" in result
assert "troubleshooting_detailed" in result
assert "prerequisites_detailed" in result
assert "next_steps_detailed" in result
assert "use_cases" in result
def test_enhance_guide_error_fallback(self):
"""Test graceful fallback on enhancement error"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
with patch.object(enhancer, 'enhance_guide', side_effect=Exception('API error')):
with patch.object(enhancer, "enhance_guide", side_effect=Exception("API error")):
guide_data = {
'title': 'Test',
'steps': [],
'language': 'python',
'prerequisites': [],
'description': 'Test'
"title": "Test",
"steps": [],
"language": "python",
"prerequisites": [],
"description": "Test",
}
# Should not raise exception - graceful fallback
try:
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
result = enhancer.enhance_guide(guide_data)
# In none mode with error, returns original
assert result['title'] == guide_data['title']
assert result["title"] == guide_data["title"]
except Exception:
pytest.fail("Should handle errors gracefully")
@@ -415,36 +404,39 @@ class TestGuideEnhancerFullWorkflow:
class TestGuideEnhancerLocalMode:
"""Test LOCAL mode (Claude Code CLI)"""
@patch('subprocess.run')
@patch("subprocess.run")
def test_call_claude_local_success(self, mock_run):
"""Test successful LOCAL mode call"""
mock_run.return_value = MagicMock(
returncode=0,
stdout=json.dumps({
'step_descriptions': [],
'troubleshooting': [],
'prerequisites_detailed': [],
'next_steps': [],
'use_cases': []
})
stdout=json.dumps(
{
"step_descriptions": [],
"troubleshooting": [],
"prerequisites_detailed": [],
"next_steps": [],
"use_cases": [],
}
),
)
enhancer = GuideEnhancer(mode='local')
if enhancer.mode == 'local':
enhancer = GuideEnhancer(mode="local")
if enhancer.mode == "local":
prompt = "Test prompt"
result = enhancer._call_claude_local(prompt)
assert result is not None
assert mock_run.called
@patch('subprocess.run')
@patch("subprocess.run")
def test_call_claude_local_timeout(self, mock_run):
"""Test LOCAL mode timeout handling"""
from subprocess import TimeoutExpired
mock_run.side_effect = TimeoutExpired('claude', 300)
enhancer = GuideEnhancer(mode='local')
if enhancer.mode == 'local':
mock_run.side_effect = TimeoutExpired("claude", 300)
enhancer = GuideEnhancer(mode="local")
if enhancer.mode == "local":
prompt = "Test prompt"
result = enhancer._call_claude_local(prompt)
@@ -456,47 +448,45 @@ class TestGuideEnhancerPromptGeneration:
def test_create_enhancement_prompt(self):
"""Test comprehensive enhancement prompt generation"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
guide_data = {
'title': 'How to Test',
'steps': [
{'description': 'Write test', 'code': 'def test_example(): pass'}
],
'language': 'python',
'prerequisites': ['pytest']
"title": "How to Test",
"steps": [{"description": "Write test", "code": "def test_example(): pass"}],
"language": "python",
"prerequisites": ["pytest"],
}
prompt = enhancer._create_enhancement_prompt(guide_data)
assert 'How to Test' in prompt
assert 'pytest' in prompt
assert 'STEP_DESCRIPTIONS' in prompt
assert 'TROUBLESHOOTING' in prompt
assert 'PREREQUISITES' in prompt
assert 'NEXT_STEPS' in prompt
assert 'USE_CASES' in prompt
assert 'JSON' in prompt
assert "How to Test" in prompt
assert "pytest" in prompt
assert "STEP_DESCRIPTIONS" in prompt
assert "TROUBLESHOOTING" in prompt
assert "PREREQUISITES" in prompt
assert "NEXT_STEPS" in prompt
assert "USE_CASES" in prompt
assert "JSON" in prompt
def test_format_steps_for_prompt(self):
"""Test step formatting for prompts"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
steps = [
{'description': 'Import', 'code': 'import requests'},
{'description': 'Create', 'code': 'obj = Object()'}
{"description": "Import", "code": "import requests"},
{"description": "Create", "code": "obj = Object()"},
]
formatted = enhancer._format_steps_for_prompt(steps)
assert 'Step 1' in formatted
assert 'Step 2' in formatted
assert 'import requests' in formatted
assert 'obj = Object()' in formatted
assert "Step 1" in formatted
assert "Step 2" in formatted
assert "import requests" in formatted
assert "obj = Object()" in formatted
def test_format_steps_empty(self):
"""Test formatting empty steps list"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
formatted = enhancer._format_steps_for_prompt([])
assert formatted == "No steps provided"
@@ -506,61 +496,57 @@ class TestGuideEnhancerResponseParsing:
def test_parse_enhancement_response_valid_json(self):
"""Test parsing valid JSON response"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
response = json.dumps({
'step_descriptions': [
{'step_index': 0, 'explanation': 'Test', 'variations': []}
],
'troubleshooting': [],
'prerequisites_detailed': [],
'next_steps': [],
'use_cases': []
})
response = json.dumps(
{
"step_descriptions": [{"step_index": 0, "explanation": "Test", "variations": []}],
"troubleshooting": [],
"prerequisites_detailed": [],
"next_steps": [],
"use_cases": [],
}
)
guide_data = {
'title': 'Test',
'steps': [{'description': 'Test', 'code': 'test'}],
'language': 'python'
}
guide_data = {"title": "Test", "steps": [{"description": "Test", "code": "test"}], "language": "python"}
result = enhancer._parse_enhancement_response(response, guide_data)
assert 'step_enhancements' in result
assert len(result['step_enhancements']) == 1
assert "step_enhancements" in result
assert len(result["step_enhancements"]) == 1
def test_parse_enhancement_response_with_extra_text(self):
"""Test parsing JSON embedded in text"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
json_data = {
'step_descriptions': [],
'troubleshooting': [],
'prerequisites_detailed': [],
'next_steps': [],
'use_cases': []
"step_descriptions": [],
"troubleshooting": [],
"prerequisites_detailed": [],
"next_steps": [],
"use_cases": [],
}
response = f"Here's the result:\n{json.dumps(json_data)}\nDone!"
guide_data = {'title': 'Test', 'steps': [], 'language': 'python'}
guide_data = {"title": "Test", "steps": [], "language": "python"}
result = enhancer._parse_enhancement_response(response, guide_data)
# Should extract JSON successfully
assert 'title' in result
assert "title" in result
def test_parse_enhancement_response_invalid_json(self):
"""Test handling invalid JSON"""
enhancer = GuideEnhancer(mode='none')
enhancer = GuideEnhancer(mode="none")
response = "This is not valid JSON"
guide_data = {'title': 'Test', 'steps': [], 'language': 'python'}
guide_data = {"title": "Test", "steps": [], "language": "python"}
result = enhancer._parse_enhancement_response(response, guide_data)
# Should return original guide_data on parse error
assert result['title'] == 'Test'
assert result["title"] == "Test"
if __name__ == '__main__':
pytest.main([__file__, '-v'])
if __name__ == "__main__":
pytest.main([__file__, "-v"])