"""Unit tests for PubMed tool.""" import json from unittest.mock import AsyncMock, MagicMock import pytest from src.tools.pubmed import PubMedTool # Sample PubMed XML response for mocking SAMPLE_PUBMED_XML = """ 12345678
Testosterone Therapy for HSDD Testosterone shows efficacy in HSDD... Smith John 2024 01
""" class TestPubMedTool: """Tests for PubMedTool.""" @pytest.mark.asyncio async def test_search_returns_evidence(self, mocker): """PubMedTool should return Evidence objects from search.""" # Mock the HTTP responses mock_search_response = MagicMock() mock_search_response.json.return_value = {"esearchresult": {"idlist": ["12345678"]}} mock_search_response.raise_for_status = MagicMock() mock_fetch_xml = """ 12345678
Testosterone and Libido Testosterone improves libido. DoeJohn 2024
12345678
""" mock_fetch_response = MagicMock() mock_fetch_response.text = mock_fetch_xml mock_fetch_response.raise_for_status = MagicMock() mock_client = AsyncMock() mock_client.get = AsyncMock(side_effect=[mock_search_response, mock_fetch_response]) mock_client.__aenter__ = AsyncMock(return_value=mock_client) mock_client.__aexit__ = AsyncMock(return_value=None) mocker.patch("httpx.AsyncClient", return_value=mock_client) # Act tool = PubMedTool() results = await tool.search("testosterone libido") # Assert assert len(results) == 1 assert results[0].citation.source == "pubmed" assert "Testosterone" in results[0].citation.title assert "12345678" in results[0].citation.url @pytest.mark.asyncio async def test_search_empty_results(self, mocker): """PubMedTool should return empty list when no results.""" mock_response = MagicMock() mock_response.json.return_value = {"esearchresult": {"idlist": []}} mock_response.raise_for_status = MagicMock() mock_client = AsyncMock() mock_client.get = AsyncMock(return_value=mock_response) mock_client.__aenter__ = AsyncMock(return_value=mock_client) mock_client.__aexit__ = AsyncMock(return_value=None) mocker.patch("httpx.AsyncClient", return_value=mock_client) tool = PubMedTool() results = await tool.search("xyznonexistentquery123") assert results == [] def test_parse_pubmed_xml(self): """PubMedTool should correctly parse XML.""" tool = PubMedTool() results = tool._parse_pubmed_xml(SAMPLE_PUBMED_XML) assert len(results) == 1 assert results[0].citation.source == "pubmed" assert "Smith John" in results[0].citation.authors @pytest.mark.asyncio async def test_search_preprocesses_query(self, mocker): """Test that queries are preprocessed before search.""" mock_search_response = MagicMock() mock_search_response.json.return_value = {"esearchresult": {"idlist": []}} mock_search_response.raise_for_status = MagicMock() mock_client = AsyncMock() mock_client.get = AsyncMock(return_value=mock_search_response) mock_client.__aenter__ = AsyncMock(return_value=mock_client) mock_client.__aexit__ = AsyncMock(return_value=None) mocker.patch("httpx.AsyncClient", return_value=mock_client) tool = PubMedTool() await tool.search("What medications help with Low Libido?") # Verify call args call_args = mock_client.get.call_args params = call_args[1]["params"] term = params["term"] # "what" and "help" should be stripped assert "what" not in term.lower() assert "help" not in term.lower() # "low libido" should be expanded assert "HSDD" in term or "hypoactive" in term @pytest.mark.asyncio async def test_search_handles_maintenance_page(self, mocker): """PubMedTool should gracefully handle non-JSON responses (maintenance pages).""" # Mock response that returns HTML instead of JSON (maintenance page) mock_response = MagicMock() mock_response.status_code = 200 mock_response.text = "Service Temporarily Unavailable" mock_response.json.side_effect = json.JSONDecodeError("Expecting value", "", 0) mock_response.raise_for_status = MagicMock() mock_client = AsyncMock() mock_client.get = AsyncMock(return_value=mock_response) mock_client.__aenter__ = AsyncMock(return_value=mock_client) mock_client.__aexit__ = AsyncMock(return_value=None) mocker.patch("httpx.AsyncClient", return_value=mock_client) tool = PubMedTool() # Should return empty list, not crash results = await tool.search("test query") assert results == []