study-buddy / tests /test_tutor_lesson.py
GitHub Actions
deploy b3d187d69e5df10bb2ec396e89f539f853465a06
14184e3
Raw
History Blame Contribute Delete
4.23 kB
import pytest
from unittest.mock import MagicMock
from app.agents.tutor_agent import TutorAgent
from app.schemas.graph import HTML5VisualPayload, NodeData
class AsyncIterator:
def __init__(self, items):
self.items = items
def __aiter__(self):
return self
async def __anext__(self):
if not self.items:
raise StopAsyncIteration
return self.items.pop(0)
@pytest.mark.asyncio
async def test_stream_lesson_content_only():
tutor = TutorAgent.__new__(TutorAgent)
mock_client = MagicMock()
tutor._client = mock_client
mock_client.stream_complete.return_value = AsyncIterator(["This ", "is ", "a ", "lesson."])
node = NodeData(id="n1", label="Smart Pace", status="ongoing")
chunks = [{"source": "adam.pdf", "text": "Adam optimizer uses moment estimation."}]
tokens = []
async for token in tutor.stream_lesson(node, chunks, "high_school", "content_only"):
tokens.append(token)
assert "".join(tokens) == "This is a lesson."
mock_client.stream_complete.assert_called_once()
messages = mock_client.stream_complete.call_args[0][0]
assert len(messages) == 2
assert "Smart Pace" in messages[1]["content"]
assert "Base the lesson EXCLUSIVELY on the provided source material" in messages[0]["content"]
@pytest.mark.asyncio
async def test_stream_lesson_net_support():
tutor = TutorAgent.__new__(TutorAgent)
mock_client = MagicMock()
tutor._client = mock_client
mock_client.stream_complete.return_value = AsyncIterator(["This ", "is ", "web ", "lesson."])
node = NodeData(id="n1", label="Smart Pace", status="ongoing")
chunks = [{"source": "adam.pdf", "text": "Adam optimizer uses moment estimation."}]
web_context = "Smart Pace is a new dynamic step size method."
tokens = []
async for token in tutor.stream_lesson(
node, chunks, "high_school", "net_support", web_context=web_context
):
tokens.append(token)
assert "".join(tokens) == "This is web lesson."
mock_client.stream_complete.assert_called_once()
messages = mock_client.stream_complete.call_args[0][0]
assert "WEB SOURCE MATERIAL:" in messages[1]["content"]
assert "Smart Pace is a new dynamic step size method." in messages[1]["content"]
assert "Ground your explanation in the provided SOURCE MATERIAL and WEB SOURCE MATERIAL" in messages[0]["content"]
def test_repair_visual_blank_render_error_gets_blank_render_guidance():
tutor = TutorAgent.__new__(TutorAgent)
mock_client = MagicMock()
tutor._client = mock_client
fake_payload = HTML5VisualPayload(html_code="<html></html>", animation_type="3d")
mock_client.structured_complete.return_value = fake_payload
result = tutor.repair_visual(
original_html="<html>original</html>",
error_message="BlankRender: no renderable objects were added within 900ms",
)
assert result is fake_payload
mock_client.structured_complete.assert_called_once()
messages = mock_client.structured_complete.call_args[0][0]
system_content = messages[0]["content"]
assert "did NOT crash" in system_content
assert "group.add(...)" in system_content
assert "return { ... }" in system_content or "return {" in system_content
assert "scene.add(...)" in system_content
def test_repair_visual_regular_error_gets_normal_crash_prompt():
tutor = TutorAgent.__new__(TutorAgent)
mock_client = MagicMock()
tutor._client = mock_client
fake_payload = HTML5VisualPayload(html_code="<html></html>", animation_type="2d_anim")
mock_client.structured_complete.return_value = fake_payload
result = tutor.repair_visual(
original_html="<html>original</html>",
error_message="ReferenceError: foo is not defined",
)
assert result is fake_payload
mock_client.structured_complete.assert_called_once()
messages = mock_client.structured_complete.call_args[0][0]
system_content = messages[0]["content"]
assert "Fix the JavaScript error and return the corrected complete HTML." in system_content
assert "did NOT crash" not in system_content
assert "group.add(...)" not in system_content