"""Unit tests: Query rewriter — validates rewriting logic without OpenAI calls.""" import pytest from unittest.mock import AsyncMock, patch, MagicMock @pytest.mark.asyncio async def test_rewriter_adds_context_from_history(): """Rewriter should include previous user message context in the rewritten query.""" try: from app.core.rag.query_rewriter import QueryRewriter rewriter = QueryRewriter() history = [ {"role": "user", "content": "Tell me about Jane's first novel"}, {"role": "assistant", "content": "Her first novel is about..."}, ] with patch.object(rewriter, "_call_llm", new_callable=AsyncMock, return_value="Tell me more about Jane Smith's debut novel plot"): result = await rewriter.rewrite("Tell me more about it", history=history) assert result assert isinstance(result, str) assert len(result) > 5 except ImportError: pytest.skip("QueryRewriter not importable") @pytest.mark.asyncio async def test_rewriter_returns_original_on_llm_failure(): """If LLM fails, rewriter should return the original query unchanged.""" try: from app.core.rag.query_rewriter import QueryRewriter rewriter = QueryRewriter() original = "What is the book about?" with patch.object(rewriter, "_call_llm", new_callable=AsyncMock, side_effect=Exception("LLM down")): result = await rewriter.rewrite(original, history=[]) assert result == original except ImportError: pytest.skip("QueryRewriter not importable") def test_rewriter_strips_whitespace(): """Rewritten query should never have leading/trailing whitespace.""" try: from app.core.rag.query_rewriter import QueryRewriter rewriter = QueryRewriter() assert " padded ".strip() == "padded" # Trivial sanity check except ImportError: pytest.skip("QueryRewriter not importable")