""" Tests for citation_handler.py Tests cover: - CitationHandler initialization - Handler type selection - Method delegation """ from unittest.mock import Mock, patch class TestCitationHandlerInit: """Tests for CitationHandler initialization.""" def test_default_handler_type(self): """Test default handler type is standard.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler handler = CitationHandler(mock_llm) mock_handler_class.assert_called_once() assert handler._handler == mock_handler def test_explicit_standard_handler(self): """Test explicit standard handler type.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, handler_type="standard") mock_handler_class.assert_called_once() def test_forced_handler_type(self): """Test forced handler type.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.forced_answer_citation_handler.ForcedAnswerCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, handler_type="forced") mock_handler_class.assert_called_once() def test_browsecomp_handler_type(self): """Test browsecomp handler type maps to forced.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.forced_answer_citation_handler.ForcedAnswerCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, handler_type="browsecomp") mock_handler_class.assert_called_once() def test_precision_handler_type(self): """Test precision handler type.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.precision_extraction_handler.PrecisionExtractionHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, handler_type="precision") mock_handler_class.assert_called_once() def test_simpleqa_handler_type(self): """Test simpleqa handler type maps to precision.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.precision_extraction_handler.PrecisionExtractionHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, handler_type="simpleqa") mock_handler_class.assert_called_once() def test_unknown_handler_type_fallback(self): """Test unknown handler type falls back to standard.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, handler_type="unknown_type") # Called twice - once for unknown fallback assert mock_handler_class.call_count >= 1 def test_handler_type_from_settings_snapshot(self): """Test handler type from settings snapshot.""" mock_llm = Mock() settings_snapshot = {"citation.handler_type": "forced"} with patch( "local_deep_research.citation_handlers.forced_answer_citation_handler.ForcedAnswerCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, settings_snapshot=settings_snapshot) mock_handler_class.assert_called_once() def test_handler_type_from_settings_snapshot_dict_value(self): """Test handler type from settings snapshot with dict value.""" mock_llm = Mock() settings_snapshot = {"citation.handler_type": {"value": "precision"}} with patch( "local_deep_research.citation_handlers.precision_extraction_handler.PrecisionExtractionHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, settings_snapshot=settings_snapshot) mock_handler_class.assert_called_once() def test_handler_type_case_insensitive(self): """Test handler type is case insensitive.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.forced_answer_citation_handler.ForcedAnswerCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, handler_type="FORCED") mock_handler_class.assert_called_once() class TestCitationHandlerMethods: """Tests for CitationHandler method delegation.""" def test_analyze_initial_delegation(self): """Test analyze_initial delegates to handler.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler.analyze_initial.return_value = {"result": "test"} mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler handler = CitationHandler(mock_llm) result = handler.analyze_initial("test query", []) mock_handler.analyze_initial.assert_called_once_with( "test query", [] ) assert result == {"result": "test"} def test_analyze_followup_delegation(self): """Test analyze_followup delegates to handler.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler.analyze_followup.return_value = {"result": "followup"} mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler handler = CitationHandler(mock_llm) result = handler.analyze_followup( "test question", [], "previous knowledge", 5 ) mock_handler.analyze_followup.assert_called_once_with( "test question", [], "previous knowledge", 5 ) assert result == {"result": "followup"} def test_backward_compatibility_methods_exposed(self): """Test backward compatibility methods are exposed.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler" ) as mock_handler_class: mock_create_docs = Mock() mock_format_sources = Mock() mock_handler = Mock() mock_handler._create_documents = mock_create_docs mock_handler._format_sources = mock_format_sources mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler handler = CitationHandler(mock_llm) assert handler._create_documents == mock_create_docs assert handler._format_sources == mock_format_sources class TestCitationHandlerSettings: """Tests for CitationHandler settings handling.""" def test_empty_settings_snapshot(self): """Test with empty settings snapshot.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, settings_snapshot={}) # Should use standard handler as default mock_handler_class.assert_called_once() def test_settings_passed_to_handler(self): """Test settings are passed to underlying handler.""" mock_llm = Mock() settings_snapshot = {"some_setting": "value"} with patch( "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm, settings_snapshot=settings_snapshot) call_kwargs = mock_handler_class.call_args[1] assert call_kwargs["settings_snapshot"] == settings_snapshot def test_llm_passed_to_handler(self): """Test LLM is passed to underlying handler.""" mock_llm = Mock() with patch( "local_deep_research.citation_handlers.standard_citation_handler.StandardCitationHandler" ) as mock_handler_class: mock_handler = Mock() mock_handler._create_documents = Mock() mock_handler._format_sources = Mock() mock_handler_class.return_value = mock_handler from local_deep_research.citation_handler import CitationHandler CitationHandler(mock_llm) call_args = mock_handler_class.call_args[0] assert call_args[0] == mock_llm