Files
wehub-resource-sync 7a0da7932b
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
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

1490 lines
53 KiB
Python

"""
Behavioral tests for citation_formatter module.
Tests CitationFormatter, QuartoExporter, RISExporter, and LaTeXExporter classes.
"""
class TestCitationModeEnum:
"""Tests for CitationMode enum."""
def test_number_hyperlinks_mode_exists(self):
"""NUMBER_HYPERLINKS mode exists."""
from local_deep_research.text_optimization.citation_formatter import (
CitationMode,
)
assert hasattr(CitationMode, "NUMBER_HYPERLINKS")
def test_domain_hyperlinks_mode_exists(self):
"""DOMAIN_HYPERLINKS mode exists."""
from local_deep_research.text_optimization.citation_formatter import (
CitationMode,
)
assert hasattr(CitationMode, "DOMAIN_HYPERLINKS")
def test_domain_id_hyperlinks_mode_exists(self):
"""DOMAIN_ID_HYPERLINKS mode exists."""
from local_deep_research.text_optimization.citation_formatter import (
CitationMode,
)
assert hasattr(CitationMode, "DOMAIN_ID_HYPERLINKS")
def test_domain_id_always_hyperlinks_mode_exists(self):
"""DOMAIN_ID_ALWAYS_HYPERLINKS mode exists."""
from local_deep_research.text_optimization.citation_formatter import (
CitationMode,
)
assert hasattr(CitationMode, "DOMAIN_ID_ALWAYS_HYPERLINKS")
def test_no_hyperlinks_mode_exists(self):
"""NO_HYPERLINKS mode exists."""
from local_deep_research.text_optimization.citation_formatter import (
CitationMode,
)
assert hasattr(CitationMode, "NO_HYPERLINKS")
def test_mode_values_are_strings(self):
"""All mode values are strings."""
from local_deep_research.text_optimization.citation_formatter import (
CitationMode,
)
for mode in CitationMode:
assert isinstance(mode.value, str)
class TestCitationFormatterInit:
"""Tests for CitationFormatter initialization."""
def test_default_mode_is_number_hyperlinks(self):
"""Default mode is NUMBER_HYPERLINKS."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter()
assert formatter.mode == CitationMode.NUMBER_HYPERLINKS
def test_accepts_custom_mode(self):
"""Accepts custom citation mode."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
assert formatter.mode == CitationMode.DOMAIN_HYPERLINKS
def test_has_citation_pattern(self):
"""Has compiled citation pattern regex."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
assert formatter.citation_pattern is not None
def test_has_comma_citation_pattern(self):
"""Has compiled comma citation pattern regex."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
assert formatter.comma_citation_pattern is not None
def test_has_source_word_pattern(self):
"""Has compiled source word pattern regex."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
assert formatter.source_word_pattern is not None
class TestCitationFormatterExtractDomain:
"""Tests for _extract_domain method."""
def test_extracts_simple_domain(self):
"""Extracts simple domain from URL."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
result = formatter._extract_domain("https://example.com/page")
assert result == "example.com"
def test_removes_www_prefix(self):
"""Removes www. prefix from domain."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
result = formatter._extract_domain("https://www.example.com/page")
assert result == "example.com"
def test_recognizes_known_domains(self):
"""Recognizes and preserves known domains."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
known_urls = [
("https://arxiv.org/abs/1234", "arxiv.org"),
("https://github.com/user/repo", "github.com"),
("https://reddit.com/r/test", "reddit.com"),
("https://youtube.com/watch", "youtube.com"),
("https://pypi.org/project/test", "pypi.org"),
("https://milvus.io/docs", "milvus.io"),
("https://medium.com/article", "medium.com"),
]
for url, expected in known_urls:
result = formatter._extract_domain(url)
assert result == expected, f"Failed for {url}"
def test_handles_subdomain(self):
"""Handles subdomain in URL."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
result = formatter._extract_domain("https://docs.python.org/page")
assert result == "python.org"
def test_handles_invalid_url(self):
"""Returns 'source' for invalid URL."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
result = formatter._extract_domain("not-a-valid-url")
# Should return something sensible, not crash
assert isinstance(result, str)
def test_handles_empty_url(self):
"""Handles empty URL string."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
result = formatter._extract_domain("")
assert isinstance(result, str)
class TestCitationFormatterFindSourcesSection:
"""Tests for _find_sources_section method."""
def test_finds_sources_header(self):
"""Finds ## Sources header."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Some content\n\n## Sources\n\n[1] Source one"
result = formatter._find_sources_section(content)
assert result != -1
assert content[result:].startswith("## Sources")
def test_finds_references_header(self):
"""Finds ## References header."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Some content\n\n## References\n\n[1] Ref one"
result = formatter._find_sources_section(content)
assert result != -1
def test_finds_bibliography_header(self):
"""Finds ## Bibliography header."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Some content\n\n## Bibliography\n\n[1] Bib one"
result = formatter._find_sources_section(content)
assert result != -1
def test_finds_citations_header(self):
"""Finds ## Citations header."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Some content\n\n## Citations\n\n[1] Citation one"
result = formatter._find_sources_section(content)
assert result != -1
def test_case_insensitive(self):
"""Finds sources header case-insensitively."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Some content\n\n## SOURCES\n\n[1] Source one"
result = formatter._find_sources_section(content)
assert result != -1
def test_returns_minus_one_when_not_found(self):
"""Returns -1 when no sources section found."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Some content without sources section."
result = formatter._find_sources_section(content)
assert result == -1
def test_finds_single_hash_header(self):
"""Finds # Sources header."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Some content\n\n# Sources\n\n[1] Source one"
result = formatter._find_sources_section(content)
assert result != -1
def test_finds_triple_hash_header(self):
"""Finds ### Sources header."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Some content\n\n### Sources\n\n[1] Source one"
result = formatter._find_sources_section(content)
assert result != -1
class TestCitationFormatterParseSources:
"""Tests for _parse_sources method."""
def test_parses_single_source(self):
"""Parses a single source entry."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
sources_content = "[1] Test Source Title\n URL: https://example.com"
result = formatter._parse_sources(sources_content)
assert "1" in result
assert result["1"][0] == "Test Source Title"
assert result["1"][1] == "https://example.com"
def test_parses_multiple_sources(self):
"""Parses multiple source entries."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
sources_content = """[1] First Source
URL: https://first.com
[2] Second Source
URL: https://second.com"""
result = formatter._parse_sources(sources_content)
assert "1" in result
assert "2" in result
def test_parses_source_without_url(self):
"""Parses source without URL."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
sources_content = "[1] Source Without URL"
result = formatter._parse_sources(sources_content)
assert "1" in result
assert result["1"][1] == "" # Empty URL
def test_parses_comma_separated_citation_numbers(self):
"""Parses comma-separated citation numbers like [36, 3]."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
sources_content = (
"[36, 3] Shared Source Title\n URL: https://shared.com"
)
result = formatter._parse_sources(sources_content)
assert "36" in result
assert "3" in result
assert result["36"][0] == "Shared Source Title"
assert result["3"][0] == "Shared Source Title"
def test_returns_empty_dict_for_empty_content(self):
"""Returns empty dict for empty content."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
result = formatter._parse_sources("")
assert result == {}
class TestCitationFormatterFormatDocument:
"""Tests for format_document method."""
def test_returns_unchanged_for_no_hyperlinks_mode(self):
"""Returns unchanged content in NO_HYPERLINKS mode."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.NO_HYPERLINKS)
content = "Text with [1] citation.\n\n## Sources\n\n[1] Source\n URL: https://test.com"
result = formatter.format_document(content)
assert result == content
def test_returns_unchanged_when_no_sources_section(self):
"""Returns unchanged when no sources section found."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with [1] citation but no sources section."
result = formatter.format_document(content)
assert result == content
def test_formats_number_hyperlinks(self):
"""Formats citations with number hyperlinks."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.NUMBER_HYPERLINKS)
content = "See [1] for details.\n\n## Sources\n\n[1] Test Source\n URL: https://test.com"
result = formatter.format_document(content)
assert "[[1]](https://test.com)" in result
def test_formats_domain_hyperlinks(self):
"""Formats citations with domain hyperlinks."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
content = "See [1] for details.\n\n## Sources\n\n[1] Test Source\n URL: https://example.com/page"
result = formatter.format_document(content)
assert "example.com" in result
def test_preserves_sources_section(self):
"""Preserves the sources section unchanged."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
sources_section = (
"## Sources\n\n[1] Test Source\n URL: https://test.com"
)
content = f"See [1] here.\n\n{sources_section}"
result = formatter.format_document(content)
assert sources_section in result
class TestCitationFormatterFormatNumberHyperlinks:
"""Tests for _format_number_hyperlinks method."""
def test_formats_single_citation(self):
"""Formats a single citation with number hyperlink."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with [1] here."
sources = {"1": ("Title", "https://example.com")}
result = formatter._format_number_hyperlinks(content, sources)
assert "[[1]](https://example.com)" in result
def test_formats_comma_separated_citations(self):
"""Formats comma-separated citations."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with [1, 2] here."
sources = {
"1": ("Title 1", "https://one.com"),
"2": ("Title 2", "https://two.com"),
}
result = formatter._format_number_hyperlinks(content, sources)
assert "[[1]](https://one.com)" in result
assert "[[2]](https://two.com)" in result
def test_formats_source_word_pattern(self):
"""Formats 'Source X' patterns."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "According to Source 1, this is true."
sources = {"1": ("Title", "https://example.com")}
result = formatter._format_number_hyperlinks(content, sources)
assert "[[1]](https://example.com)" in result
def test_leaves_citation_without_url_unchanged(self):
"""Leaves citation without URL unchanged."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with [1] here."
sources = {"1": ("Title", "")} # No URL
result = formatter._format_number_hyperlinks(content, sources)
assert "[1]" in result
# Should not have hyperlink
assert "[[1]](" not in result
class TestCitationFormatterFormatDomainHyperlinks:
"""Tests for _format_domain_hyperlinks method."""
def test_replaces_number_with_domain(self):
"""Replaces citation number with domain."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with [1] here."
sources = {"1": ("Title", "https://github.com/repo")}
result = formatter._format_domain_hyperlinks(content, sources)
assert "github.com" in result
def test_handles_comma_separated_citations(self):
"""Handles comma-separated citations with domains."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with [1, 2] here."
sources = {
"1": ("Title 1", "https://github.com"),
"2": ("Title 2", "https://arxiv.org"),
}
result = formatter._format_domain_hyperlinks(content, sources)
assert "github.com" in result
assert "arxiv.org" in result
class TestCitationFormatterFormatDomainIdHyperlinks:
"""Tests for _format_domain_id_hyperlinks method."""
def test_no_id_for_single_domain_citation(self):
"""No ID suffix when only one citation from domain."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with [1] here."
sources = {"1": ("Title", "https://github.com/repo")}
result = formatter._format_domain_id_hyperlinks(content, sources)
assert "[[github.com]](" in result
assert "-1" not in result.split("github.com")[1].split("]")[0]
def test_adds_id_for_multiple_domain_citations(self):
"""Adds ID suffix when multiple citations from same domain."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with [1] and [2] here."
sources = {
"1": ("Title 1", "https://github.com/repo1"),
"2": ("Title 2", "https://github.com/repo2"),
}
result = formatter._format_domain_id_hyperlinks(content, sources)
assert "github.com-1" in result
assert "github.com-2" in result
class TestCitationFormatterFormatDomainIdAlwaysHyperlinks:
"""Tests for _format_domain_id_always_hyperlinks method."""
def test_always_adds_id(self):
"""Always adds ID suffix even for single citation."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with [1] here."
sources = {"1": ("Title", "https://github.com/repo")}
result = formatter._format_domain_id_always_hyperlinks(content, sources)
assert "github.com-1" in result
class TestCitationFormatterUnicodeBrackets:
"""Tests for handling Unicode lenticular brackets."""
def test_matches_unicode_lenticular_brackets(self):
"""Matches Unicode lenticular brackets 【】."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Text with 【1】 here."
sources = {"1": ("Title", "https://example.com")}
result = formatter._format_number_hyperlinks(content, sources)
assert "[[1]](https://example.com)" in result
class TestQuartoExporterInit:
"""Tests for QuartoExporter initialization."""
def test_can_instantiate(self):
"""Can instantiate QuartoExporter."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
assert exporter is not None
def test_has_citation_pattern(self):
"""Has citation pattern regex."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
assert exporter.citation_pattern is not None
def test_has_comma_citation_pattern(self):
"""Has comma citation pattern regex."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
assert exporter.comma_citation_pattern is not None
class TestQuartoExporterExportToQuarto:
"""Tests for export_to_quarto method."""
def test_adds_yaml_header(self):
"""Adds YAML front matter header."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
content = "# My Report\n\nSome content."
result = exporter.export_to_quarto(content)
assert result.startswith("---")
assert "title:" in result
def test_uses_provided_title(self):
"""Uses provided title in YAML header."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
content = "Some content."
result = exporter.export_to_quarto(content, title="Custom Title")
assert "Custom Title" in result
def test_extracts_title_from_content(self):
"""Extracts title from content if not provided."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
content = "# My Research Report\n\nSome content."
result = exporter.export_to_quarto(content)
assert "My Research Report" in result
def test_converts_citations_to_quarto_format(self):
"""Converts [1] citations to [@ref1] format."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
content = "See [1] for details."
result = exporter.export_to_quarto(content)
assert "[@ref1]" in result
def test_converts_comma_separated_citations(self):
"""Converts comma-separated citations to Quarto format."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
content = "See [1, 2, 3] for details."
result = exporter.export_to_quarto(content)
assert "@ref1" in result
assert "@ref2" in result
assert "@ref3" in result
def test_adds_bibliography_note(self):
"""Adds bibliography file note."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
content = (
"Content.\n\n## Sources\n\n[1] Source One\n URL: https://test.com"
)
result = exporter.export_to_quarto(content)
assert "references.bib" in result
class TestQuartoExporterGenerateBibliography:
"""Tests for _generate_bibliography method."""
def test_generates_bibtex_entries(self):
"""Generates BibTeX entries from sources."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
content = "[1] Test Source Title\n URL: https://example.com"
result = exporter._generate_bibliography(content)
assert "@misc{ref1" in result
# BibTeX uses braces and quotes: title = "{Title}"
assert "Test Source Title" in result
assert "title" in result
def test_includes_url_in_bibtex(self):
"""Includes URL in BibTeX entry."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
content = "[1] Test Source Title\n URL: https://example.com"
result = exporter._generate_bibliography(content)
assert "url = {https://example.com}" in result
def test_generates_multiple_entries(self):
"""Generates multiple BibTeX entries."""
from local_deep_research.text_optimization.citation_formatter import (
QuartoExporter,
)
exporter = QuartoExporter()
content = "[1] First Source\n URL: https://first.com\n[2] Second Source\n URL: https://second.com"
result = exporter._generate_bibliography(content)
assert "@misc{ref1" in result
assert "@misc{ref2" in result
class TestRISExporterInit:
"""Tests for RISExporter initialization."""
def test_can_instantiate(self):
"""Can instantiate RISExporter."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
assert exporter is not None
def test_has_sources_pattern(self):
"""Has sources pattern regex."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
assert exporter.sources_pattern is not None
class TestRISExporterExportToRIS:
"""Tests for export_to_ris method."""
def test_returns_empty_for_no_sources(self):
"""Returns empty string when no sources section."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
content = "Content without sources section."
result = exporter.export_to_ris(content)
assert result == ""
def test_finds_sources_section(self):
"""Finds ## Sources section."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
content = "Content.\n\n## Sources\n\n[1] Test Source\n URL: https://test.com"
result = exporter.export_to_ris(content)
assert "TY - ELEC" in result
def test_finds_references_section(self):
"""Finds ## References section."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
content = "Content.\n\n## References\n\n[1] Test Ref\n URL: https://test.com"
result = exporter.export_to_ris(content)
assert "TY - ELEC" in result
def test_includes_title(self):
"""Includes title in RIS entry."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
content = "## Sources\n\n[1] My Test Title"
result = exporter.export_to_ris(content)
assert "TI -" in result
def test_includes_url(self):
"""Includes URL in RIS entry."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
content = "## Sources\n\n[1] Test Source\nURL: https://example.com"
result = exporter.export_to_ris(content)
assert "UR - https://example.com" in result
def test_includes_end_of_reference(self):
"""Includes ER - end of reference marker."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
content = "## Sources\n\n[1] Test Source"
result = exporter.export_to_ris(content)
assert "ER -" in result
def test_includes_language(self):
"""Includes language field in RIS."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
content = "## Sources\n\n[1] Test Source"
result = exporter.export_to_ris(content)
assert "LA - en" in result
class TestRISExporterCreateRISEntry:
"""Tests for _create_ris_entry method."""
def test_creates_entry_with_id(self):
"""Creates RIS entry with reference ID."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
result = exporter._create_ris_entry("1", "Test Title")
assert "ID - ref1" in result
def test_extracts_year_from_text(self):
"""Extracts year from text if present."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
result = exporter._create_ris_entry("1", "Test Title published in 2023")
assert "PY - 2023" in result
def test_extracts_doi_from_metadata(self):
"""Extracts DOI from metadata."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
result = exporter._create_ris_entry(
"1", "Test Title", metadata={"doi": "10.1234/test"}
)
assert "DO - 10.1234/test" in result
def test_extracts_publisher_from_github_url(self):
"""Extracts GitHub as publisher from URL."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
result = exporter._create_ris_entry(
"1", "Test Title", url="https://github.com/user/repo"
)
assert "PB - GitHub" in result
def test_extracts_publisher_from_arxiv_url(self):
"""Extracts arXiv as publisher from URL."""
from local_deep_research.text_optimization.citation_formatter import (
RISExporter,
)
exporter = RISExporter()
result = exporter._create_ris_entry(
"1", "Test Title", url="https://arxiv.org/abs/1234"
)
assert "PB - arXiv" in result
class TestLaTeXExporterInit:
"""Tests for LaTeXExporter initialization."""
def test_can_instantiate(self):
"""Can instantiate LaTeXExporter."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
assert exporter is not None
def test_has_citation_pattern(self):
"""Has citation pattern regex."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
assert exporter.citation_pattern is not None
def test_has_heading_patterns(self):
"""Has heading patterns list."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
assert len(exporter.heading_patterns) > 0
def test_has_emphasis_patterns(self):
"""Has emphasis patterns list."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
assert len(exporter.emphasis_patterns) > 0
class TestLaTeXExporterExportToLatex:
"""Tests for export_to_latex method."""
def test_adds_document_class(self):
"""Adds documentclass declaration."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("Content")
assert "\\documentclass" in result
def test_adds_begin_document(self):
"""Adds begin{document}."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("Content")
assert "\\begin{document}" in result
def test_adds_end_document(self):
"""Adds end{document}."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("Content")
assert "\\end{document}" in result
def test_converts_h1_to_section(self):
"""Converts # heading to \\section."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("# My Heading\n\nContent")
assert "\\section{My Heading}" in result
def test_converts_h2_to_subsection(self):
"""Converts ## heading to \\subsection."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("## My Subheading\n\nContent")
assert "\\subsection{My Subheading}" in result
def test_converts_h3_to_subsubsection(self):
"""Converts ### heading to \\subsubsection."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("### My Sub-Subheading\n\nContent")
assert "\\subsubsection{My Sub-Subheading}" in result
def test_converts_bold_to_textbf(self):
"""Converts **bold** to \\textbf."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("This is **bold** text.")
assert "\\textbf{bold}" in result
def test_converts_italic_to_textit(self):
"""Converts *italic* to \\textit."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("This is *italic* text.")
assert "\\textit{italic}" in result
def test_converts_code_to_texttt(self):
"""Converts `code` to \\texttt."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("This is `code` text.")
assert "\\texttt{code}" in result
def test_converts_citations_to_cite(self):
"""Converts [1] to \\cite{1}."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter.export_to_latex("See [1] for details.")
assert "\\cite{1}" in result
def test_adds_bibliography(self):
"""Adds bibliography section when sources exist."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
content = "Content.\n\n## Sources\n\n[1] Test Source\n URL: https://test.com"
result = exporter.export_to_latex(content)
assert "\\begin{thebibliography}" in result
assert "\\end{thebibliography}" in result
class TestLaTeXExporterConvertLists:
"""Tests for _convert_lists method."""
def test_converts_bullet_to_item(self):
"""Converts - bullet to \\item."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._convert_lists("- First item\n- Second item")
assert "\\item First item" in result
assert "\\item Second item" in result
def test_adds_itemize_environment(self):
"""Adds itemize environment around list."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._convert_lists("- First item\n- Second item")
assert "\\begin{itemize}" in result
assert "\\end{itemize}" in result
class TestLaTeXExporterEscapeLatex:
"""Tests for _escape_latex method."""
def test_escapes_ampersand(self):
"""Escapes & character."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._escape_latex("A & B")
assert "\\&" in result
def test_escapes_percent(self):
"""Escapes % character."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._escape_latex("50%")
assert "\\%" in result
def test_escapes_dollar(self):
"""Escapes $ character."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._escape_latex("$100")
assert "\\$" in result
def test_escapes_hash(self):
"""Escapes # character."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._escape_latex("#1")
assert "\\#" in result
def test_escapes_underscore(self):
"""Escapes _ character."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._escape_latex("file_name")
assert "\\_" in result
def test_escapes_braces(self):
"""Escapes { and } characters."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._escape_latex("{test}")
assert "\\{" in result
assert "\\}" in result
def test_escapes_tilde(self):
"""Escapes ~ character."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._escape_latex("~test")
assert "\\textasciitilde{}" in result
def test_escapes_caret(self):
"""Escapes ^ character."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._escape_latex("x^2")
assert "\\textasciicircum{}" in result
class TestLaTeXExporterCreateBibliography:
"""Tests for _create_bibliography method."""
def test_returns_empty_for_no_sources(self):
"""Returns empty string when no sources section."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
result = exporter._create_bibliography("Content without sources.")
assert result == ""
def test_creates_bibitem_entries(self):
"""Creates bibitem entries for sources."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
content = "## Sources\n\n[1] Test Source Title"
result = exporter._create_bibliography(content)
assert "\\bibitem{1}" in result
def test_includes_url_in_bibitem(self):
"""Includes URL in bibitem entry."""
from local_deep_research.text_optimization.citation_formatter import (
LaTeXExporter,
)
exporter = LaTeXExporter()
content = (
"## Sources\n\n[1] Test Source Title\n URL: https://example.com"
)
result = exporter._create_bibliography(content)
assert "\\url{https://example.com}" in result
class TestCitationFormatterFormatDocumentSplit:
"""Tests for format_document_split — answer / sources tuple return."""
def test_returns_tuple_with_answer_and_sources(self):
"""Happy path: returns hyperlinked answer and raw sources block."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.NUMBER_HYPERLINKS)
content = (
"See [1] for details.\n\n"
"## Sources\n\n[1] Test Source\n URL: https://test.com"
)
answer, sources = formatter.format_document_split(content)
assert "[[1]](https://test.com)" in answer
assert sources.startswith("## Sources")
assert "Test Source" in sources
def test_returns_empty_sources_when_no_sources_section(self):
"""No Sources section in input → returns (content, '')."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.NUMBER_HYPERLINKS)
content = "Just an answer with [1] but no Sources section."
answer, sources = formatter.format_document_split(content)
assert answer == content
assert sources == ""
def test_returns_unchanged_in_no_hyperlinks_mode(self):
"""NO_HYPERLINKS mode short-circuits to (content, '')."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.NO_HYPERLINKS)
content = (
"Text with [1].\n\n## Sources\n\n[1] Source\n URL: https://x.com"
)
answer, sources = formatter.format_document_split(content)
assert answer == content
assert sources == ""
def test_format_document_compat_equals_concatenation(self):
"""format_document() == answer + sources from format_document_split."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.NUMBER_HYPERLINKS)
content = (
"Body with [1] cite.\n\n"
"## Sources\n\n[1] One\n URL: https://one.com"
)
full = formatter.format_document(content)
answer, sources = formatter.format_document_split(content)
assert full == answer + sources
class TestCitationFormatterApplyInlineHyperlinks:
"""Tests for apply_inline_hyperlinks — structured-source delegation."""
def test_replaces_bracket_refs_with_markdown_links(self):
"""[1] [2] become [[1]](url) [[2]](url) given a structured list."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "See [1] and [2]."
sources = [
{"index": "1", "title": "First", "url": "https://a.com"},
{"index": "2", "title": "Second", "url": "https://b.com"},
]
result = formatter.apply_inline_hyperlinks(content, sources)
assert "[[1]](https://a.com)" in result
assert "[[2]](https://b.com)" in result
def test_handles_missing_index_gracefully(self):
"""[7] left unchanged when no source with index 7."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "See [1] and [7]."
sources = [
{"index": "1", "title": "Only", "url": "https://a.com"},
]
result = formatter.apply_inline_hyperlinks(content, sources)
assert "[[1]](https://a.com)" in result
# [7] should remain as-is — formatter passes through unknown indices
assert "[7]" in result
def test_handles_comma_lists(self):
"""[1, 2] becomes individual links via comma_citation_pattern."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Per [1, 2] this is true."
sources = [
{"index": "1", "title": "First", "url": "https://a.com"},
{"index": "2", "title": "Second", "url": "https://b.com"},
]
result = formatter.apply_inline_hyperlinks(content, sources)
# _format_number_hyperlinks expands comma lists into individual links
assert "https://a.com" in result
assert "https://b.com" in result
def test_skips_when_no_bracket_refs(self):
"""Content without [N] refs returns unchanged."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Plain text with no citations."
sources = [
{"index": "1", "title": "Unused", "url": "https://x.com"},
]
result = formatter.apply_inline_hyperlinks(content, sources)
assert result == content
def test_returns_content_unchanged_when_sources_empty(self):
"""Empty sources list short-circuits to content."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "See [1]."
assert formatter.apply_inline_hyperlinks(content, []) == content
def test_returns_empty_string_when_content_empty(self):
"""Empty content returns empty string, no crash."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
sources = [{"index": "1", "title": "x", "url": "https://x.com"}]
assert formatter.apply_inline_hyperlinks("", sources) == ""
assert formatter.apply_inline_hyperlinks(None, sources) == ""
def test_skips_sources_with_missing_url(self):
"""Sources missing url are filtered out before delegation."""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "See [1] and [2]."
sources = [
{"index": "1", "title": "Has URL", "url": "https://a.com"},
{"index": "2", "title": "No URL"}, # missing url key
]
result = formatter.apply_inline_hyperlinks(content, sources)
assert "[[1]](https://a.com)" in result
# [2] left unchanged because that source was filtered
assert "[2]" in result
def test_accepts_link_key_for_searxng_compatibility(self):
"""Regression: Searxng-sourced results use 'link' not 'url'.
search_engine_searxng.py emits ``{"link": url, "title": ...,
"snippet": ...}``. The langgraph-agent strategy's collector stores
these dicts verbatim in ``all_links_of_system`` and the chat-mode
fallback path (``apply_inline_hyperlinks``) consumed them. Looking
up only ``s["url"]`` silently dropped every Searxng-sourced
citation — the answer body shipped with plain ``[N]`` brackets
even though the Sources section beneath was fully populated.
Both keys must be accepted.
"""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "Per [1] and [2], yes."
sources = [
# Searxng shape
{"index": "1", "title": "Searxng result", "link": "https://sx.com"},
# Other-engine shape (still works)
{"index": "2", "title": "Other engine", "url": "https://o.com"},
]
result = formatter.apply_inline_hyperlinks(content, sources)
assert "[[1]](https://sx.com)" in result, (
"Searxng-style 'link' key must produce a hyperlink"
)
assert "[[2]](https://o.com)" in result
def test_prefers_url_over_link_when_both_present(self):
"""When a source carries both keys, ``url`` wins.
The langgraph collector copies the raw engine dict and additionally
sets ``r['link'] = r['url']`` when only ``url`` is present; other
callers may set both for legacy reasons. The canonical destination
is ``url`` — fall back to ``link`` only when ``url`` is missing.
"""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
)
formatter = CitationFormatter()
content = "See [1]."
sources = [
{
"index": "1",
"title": "Both",
"url": "https://canonical.com",
"link": "https://legacy.com",
}
]
result = formatter.apply_inline_hyperlinks(content, sources)
assert "[[1]](https://canonical.com)" in result
def test_dispatches_on_self_mode_for_domain_hyperlinks(self):
"""Regression: ``apply_inline_hyperlinks`` was hard-coded to
the NUMBER_HYPERLINKS formatter, so the chat-mode fallback
path ignored ``report.citation_format``. A user who picked
DOMAIN_HYPERLINKS in settings still got ``[[1]](url)`` on
every chat answer instead of ``[[arxiv.org]](url)``.
"""
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
content = "Per [1] and [2]."
sources = [
{"index": "1", "title": "T", "url": "https://arxiv.org/abs/123"},
{"index": "2", "title": "T", "url": "https://nytimes.com/a"},
]
result = formatter.apply_inline_hyperlinks(content, sources)
assert "[[arxiv.org]](https://arxiv.org/abs/123)" in result
assert "[[nytimes.com]](https://nytimes.com/a)" in result
assert "[[1]](" not in result # must NOT fall back to NUMBER mode
def test_dispatches_on_self_mode_for_domain_id_hyperlinks(self):
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.DOMAIN_ID_HYPERLINKS)
content = "See [1] and [2]."
sources = [
{"index": "1", "title": "T", "url": "https://arxiv.org/abs/1"},
{"index": "2", "title": "T", "url": "https://arxiv.org/abs/2"},
]
result = formatter.apply_inline_hyperlinks(content, sources)
# Smart domain numbering: same domain twice → [arxiv.org-1] /
# [arxiv.org-2] (or similar — the exact suffix is the formatter's
# business; we assert it does NOT collapse to plain [N] mode).
assert "arxiv.org" in result
assert "[[1]](" not in result
def test_dispatches_on_self_mode_for_source_tagged_hyperlinks(self):
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(
mode=CitationMode.SOURCE_TAGGED_HYPERLINKS
)
content = "Per [1] and [2]."
sources = [
{"index": "1", "title": "T", "url": "https://arxiv.org/abs/1"},
# Library hit: collection_name in metadata should win over
# the URL-derived domain tag.
{
"index": "2",
"title": "T",
"url": "https://example.com/doc",
"metadata": {"collection_name": "mypapers"},
},
]
result = formatter.apply_inline_hyperlinks(content, sources)
# arxiv URL → [arxiv-1] (URLClassifier tag), collection → [mypapers-2].
assert "arxiv-1" in result
assert "mypapers-2" in result
def test_no_hyperlinks_mode_returns_content_unchanged(self):
from local_deep_research.text_optimization.citation_formatter import (
CitationFormatter,
CitationMode,
)
formatter = CitationFormatter(mode=CitationMode.NO_HYPERLINKS)
content = "Per [1] and [2]."
sources = [
{"index": "1", "title": "T", "url": "https://a.com"},
{"index": "2", "title": "T", "url": "https://b.com"},
]
assert formatter.apply_inline_hyperlinks(content, sources) == content