pagepiper/tests/test_synthesizer.py
pyr0ball 17cdb552a3 fix: T7 quality — SynthesisResult.citations tuple, retriever comments, test assertion
- SynthesisResult.citations changed from list[Citation] to tuple[Citation, ...]
  so frozen=True dataclass is genuinely immutable end-to-end
- synthesize() now builds tuple via generator expression
- retriever._combined: add comment explaining L2 distance inversion
- retriever.hybrid_search: comment on _bm25._chunks private access
- test_synthesizer_builds_context_from_chunks: drop vacuous str(call_args)
  fallback; assert directly on call_args.args[0]
2026-05-04 17:51:22 -07:00

53 lines
1.7 KiB
Python

# tests/test_synthesizer.py
"""Tests for Synthesizer — mocked LLM, citation assembly."""
from __future__ import annotations
from unittest.mock import MagicMock
from app.services.retriever import RetrievedChunk
from app.services.synthesizer import Synthesizer, SynthesisResult
def _chunk(doc_id: str = "book-a", page: int = 5, text: str = "Fireball rules") -> RetrievedChunk:
return RetrievedChunk(
chunk_id="c1", doc_id=doc_id, page_number=page, text=text,
bm25_score=1.0, vector_score=None,
)
def test_synthesizer_returns_answer_and_citations():
mock_llm = MagicMock()
mock_llm.complete.return_value = "Fireball deals 8d6 damage [p.5]."
synth = Synthesizer(mock_llm)
result = synth.synthesize(
message="How does Fireball work?",
history=[],
chunks=[_chunk()],
)
assert isinstance(result, SynthesisResult)
assert "Fireball" in result.answer
assert len(result.citations) == 1
assert result.citations[0].page_number == 5
assert result.citations[0].doc_id == "book-a"
def test_synthesizer_builds_context_from_chunks():
mock_llm = MagicMock()
mock_llm.complete.return_value = "Answer."
synth = Synthesizer(mock_llm)
synth.synthesize("Q?", [], [_chunk(text="Detailed rule text here.")])
assert "Detailed rule text here." in mock_llm.complete.call_args.args[0]
def test_synthesizer_uses_system_prompt():
mock_llm = MagicMock()
mock_llm.complete.return_value = "Answer."
synth = Synthesizer(mock_llm)
synth.synthesize("Q?", [], [_chunk()])
call_kwargs = mock_llm.complete.call_args
assert call_kwargs.kwargs.get("system") or call_kwargs[1].get("system")