7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
335 lines
12 KiB
Python
335 lines
12 KiB
Python
"""
|
|
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
|