learningcircuit--local-deep-research
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
417 行
12 KiB
Python
417 行
12 KiB
Python
"""
|
|
Comprehensive edge case tests for citation formatter to ensure robust handling
|
|
of various citation scenarios and malformed inputs.
|
|
"""
|
|
|
|
from local_deep_research.text_optimization.citation_formatter import (
|
|
CitationFormatter,
|
|
CitationMode,
|
|
)
|
|
|
|
|
|
class TestCitationEdgeCases:
|
|
"""Test edge cases and potential bugs in citation formatting."""
|
|
|
|
def test_multiple_citations_same_sentence(self):
|
|
"""Test multiple citations in the same sentence."""
|
|
content = """# Research Report
|
|
|
|
Recent advances in AI [1] [2] have shown that transformers [3] [4] [5] are effective.
|
|
|
|
## Sources
|
|
|
|
[1] Attention Is All You Need
|
|
URL: https://arxiv.org/abs/1706.03762
|
|
|
|
[2] BERT Paper
|
|
URL: https://arxiv.org/abs/1810.04805
|
|
|
|
[3] GPT-3 Paper
|
|
URL: https://openai.com/research/gpt-3
|
|
|
|
[4] T5 Paper
|
|
URL: https://arxiv.org/abs/1910.10683
|
|
|
|
[5] RoBERTa Paper
|
|
URL: https://arxiv.org/abs/1907.11692"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# Should have correct number of citations
|
|
assert result.count("[arxiv.org]") == 4 # sources 1, 2, 4, 5
|
|
assert result.count("[openai.com]") == 1 # source 3
|
|
|
|
# Original numbers should not appear in body
|
|
body_text = result.split("## Sources")[0]
|
|
for i in range(1, 6):
|
|
assert f"[{i}]" not in body_text
|
|
|
|
def test_citations_with_punctuation(self):
|
|
"""Test citations followed by various punctuation marks."""
|
|
content = """# Research Report
|
|
|
|
This is proven [1]. Also shown [2], and demonstrated [3]; furthermore [4]: see [5]!
|
|
|
|
## Sources
|
|
|
|
[1] First Paper
|
|
URL: https://example.com/1
|
|
|
|
[2] Second Paper
|
|
URL: https://example.com/2
|
|
|
|
[3] Third Paper
|
|
URL: https://example.com/3
|
|
|
|
[4] Fourth Paper
|
|
URL: https://example.com/4
|
|
|
|
[5] Fifth Paper
|
|
URL: https://example.com/5"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_ID_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# All citations should be properly formatted
|
|
assert "[[example.com-1]](https://example.com/1)." in result
|
|
assert "[[example.com-2]](https://example.com/2)," in result
|
|
assert "[[example.com-3]](https://example.com/3);" in result
|
|
assert "[[example.com-4]](https://example.com/4):" in result
|
|
assert "[[example.com-5]](https://example.com/5)!" in result
|
|
|
|
def test_missing_url_in_source(self):
|
|
"""Test handling of sources without URLs."""
|
|
content = """# Research Report
|
|
|
|
This cites a book [1] and a paper [2].
|
|
|
|
## Sources
|
|
|
|
[1] Deep Learning Book by Goodfellow et al.
|
|
|
|
[2] Neural Networks Paper
|
|
URL: https://nature.com/article"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# Source with URL should be formatted
|
|
assert "[nature.com]" in result
|
|
# Source without URL should remain as-is
|
|
assert "[1]" in result
|
|
assert "Deep Learning Book" in result
|
|
|
|
def test_malformed_source_section(self):
|
|
"""Test handling of malformed source sections."""
|
|
content = """# Research Report
|
|
|
|
Citation here [1] and here [2].
|
|
|
|
## Sources
|
|
|
|
[1] Paper One
|
|
Some description
|
|
URL: https://arxiv.org/abs/1234.5678
|
|
|
|
[2] Paper Two URL: https://nature.com/123
|
|
Additional text
|
|
|
|
[3] Not cited in text
|
|
URL: https://unused.com/paper"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# The formatter's regex only captures URLs that are on the immediate next line
|
|
# after the title line, starting with "URL:"
|
|
|
|
# Source [1] has extra description line, so URL is not captured
|
|
assert "[1]" in result # Citation remains unchanged
|
|
assert "[arxiv.org]" not in result
|
|
|
|
# Source [2] has inline URL which won't be parsed as a URL
|
|
assert "[2]" in result # Remains unchanged
|
|
assert "[nature.com]" not in result
|
|
|
|
# Source [3] is properly formatted and would work if cited
|
|
body = result.split("## Sources")[0]
|
|
assert "[3]" not in body # Not cited in text
|
|
|
|
def test_duplicate_urls_different_sources(self):
|
|
"""Test handling of multiple sources with the same URL."""
|
|
content = """# Research Report
|
|
|
|
First reference [1] and second reference [2] to same paper.
|
|
|
|
## Sources
|
|
|
|
[1] Original Paper Title
|
|
URL: https://arxiv.org/abs/1706.03762
|
|
|
|
[2] Same Paper Different Title
|
|
URL: https://arxiv.org/abs/1706.03762"""
|
|
|
|
formatter = CitationFormatter(
|
|
mode=CitationMode.DOMAIN_ID_ALWAYS_HYPERLINKS
|
|
)
|
|
result = formatter.format_document(content)
|
|
|
|
# Both should be formatted with IDs
|
|
assert "[arxiv.org-1]" in result
|
|
assert "[arxiv.org-2]" in result
|
|
|
|
def test_citations_in_headers_and_lists(self):
|
|
"""Test citations in markdown headers and lists."""
|
|
content = """# Research Report [1]
|
|
|
|
## Introduction with Citation [2]
|
|
|
|
- First point [3]
|
|
- Second point with reference [4]
|
|
- Nested item [5]
|
|
|
|
### Subsection [6]
|
|
|
|
## Sources
|
|
|
|
[1] Header Paper
|
|
URL: https://example.com/1
|
|
|
|
[2] Intro Paper
|
|
URL: https://example.com/2
|
|
|
|
[3] List Item One
|
|
URL: https://example.com/3
|
|
|
|
[4] List Item Two
|
|
URL: https://example.com/4
|
|
|
|
[5] Nested Paper
|
|
URL: https://example.com/5
|
|
|
|
[6] Subsection Paper
|
|
URL: https://example.com/6"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_ID_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# All citations should be formatted, even in headers and lists
|
|
for i in range(1, 7):
|
|
assert f"[example.com-{i}]" in result
|
|
assert f"[{i}]" not in result.split("## Sources")[0]
|
|
|
|
def test_citations_in_code_blocks(self):
|
|
"""Test that citations inside code blocks are not formatted."""
|
|
content = """# Research Report
|
|
|
|
This is a citation [1].
|
|
|
|
```python
|
|
# This [1] should not be formatted
|
|
def cite(ref):
|
|
return f"[{ref}]" # [2] in string
|
|
```
|
|
|
|
Another citation [2].
|
|
|
|
## Sources
|
|
|
|
[1] First Paper
|
|
URL: https://arxiv.org/abs/1111.1111
|
|
|
|
[2] Second Paper
|
|
URL: https://nature.com/2222"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# Citations outside code blocks should be formatted
|
|
assert "[[arxiv.org]](https://arxiv.org/abs/1111.1111)" in result
|
|
assert "[[nature.com]](https://nature.com/2222)" in result
|
|
|
|
# Current implementation formats citations even in code blocks
|
|
# This is a known limitation - code blocks are not preserved
|
|
assert (
|
|
"# This [[arxiv.org]](https://arxiv.org/abs/1111.1111) should not be formatted"
|
|
in result
|
|
)
|
|
assert (
|
|
'return f"[{ref}]" # [[nature.com]](https://nature.com/2222) in string'
|
|
in result
|
|
)
|
|
|
|
def test_non_sequential_citations(self):
|
|
"""Test non-sequential citation numbers."""
|
|
content = """# Research Report
|
|
|
|
Citations [5] and [1] and [10].
|
|
|
|
## Sources
|
|
|
|
[1] First Paper
|
|
URL: https://first.com/paper
|
|
|
|
[5] Fifth Paper
|
|
URL: https://fifth.com/paper
|
|
|
|
[10] Tenth Paper
|
|
URL: https://tenth.com/paper"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# All citations should be formatted correctly
|
|
assert "[first.com]" in result
|
|
assert "[fifth.com]" in result
|
|
assert "[tenth.com]" in result
|
|
|
|
# Original numbers should not remain
|
|
body = result.split("## Sources")[0]
|
|
assert "[1]" not in body
|
|
assert "[5]" not in body
|
|
assert "[10]" not in body
|
|
|
|
def test_citations_with_special_urls(self):
|
|
"""Test citations with special characters in URLs."""
|
|
content = """# Research Report
|
|
|
|
Various sources [1] [2] [3] [4].
|
|
|
|
## Sources
|
|
|
|
[1] DOI Paper
|
|
URL: https://doi.org/10.1234/journal.2023.12345
|
|
|
|
[2] Paper with Query
|
|
URL: https://example.com/search?q=machine+learning&filter=2023
|
|
|
|
[3] Paper with Fragment
|
|
URL: https://example.com/paper#section-3.2
|
|
|
|
[4] Paper with Port
|
|
URL: https://repository.edu:8080/papers/123"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# All domains should be extracted correctly
|
|
assert "[doi.org]" in result
|
|
assert "[example.com]" in result
|
|
# Port numbers are included in domain extraction
|
|
assert "[repository.edu:8080]" in result
|
|
|
|
def test_empty_and_whitespace_handling(self):
|
|
"""Test handling of empty content and various whitespace."""
|
|
# Empty content
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
assert formatter.format_document("") == ""
|
|
|
|
# Only whitespace
|
|
assert formatter.format_document(" \n\n \t") == " \n\n \t"
|
|
|
|
# No sources section
|
|
content = "This has a citation [1] but no sources."
|
|
assert formatter.format_document(content) == content
|
|
|
|
def test_case_sensitivity_in_sources_header(self):
|
|
"""Test various cases for Sources section header."""
|
|
test_cases = [
|
|
"## Sources",
|
|
"## SOURCES",
|
|
"## sources",
|
|
"## Sources:",
|
|
"##Sources",
|
|
"## References", # Should not match
|
|
]
|
|
|
|
for header in test_cases[:4]:
|
|
content = f"""Citation [1].
|
|
|
|
{header}
|
|
|
|
[1] Paper
|
|
URL: https://example.com/1"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
if "References" not in header:
|
|
assert "[example.com]" in result
|
|
else:
|
|
assert "[1]" in result # Should remain unchanged
|
|
|
|
def test_unicode_and_international_domains(self):
|
|
"""Test handling of unicode and international domains."""
|
|
content = """# Research Report
|
|
|
|
Chinese research [1], Russian study [2], and emoji domain [3].
|
|
|
|
## Sources
|
|
|
|
[1] 中文论文
|
|
URL: https://研究.中国/paper
|
|
|
|
[2] Русская статья
|
|
URL: https://наука.рф/article
|
|
|
|
[3] Modern Paper
|
|
URL: https://👍.ws/research"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# Should handle international domains
|
|
assert "[研究.中国]" in result or "[xn--" in result # Punycode
|
|
assert "[наука.рф]" in result or "[xn--" in result
|
|
assert "[👍.ws]" in result or "[xn--" in result
|
|
|
|
def test_very_long_urls(self):
|
|
"""Test handling of very long URLs."""
|
|
long_path = "a" * 500
|
|
content = f"""# Research Report
|
|
|
|
Long URL citation [1].
|
|
|
|
## Sources
|
|
|
|
[1] Paper with Long URL
|
|
URL: https://example.com/{long_path}"""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# Should handle long URLs without issues
|
|
assert "[example.com]" in result
|
|
assert long_path in result # URL should be preserved in sources
|
|
|
|
def test_multiple_source_sections(self):
|
|
"""Test document with multiple sections that look like sources."""
|
|
content = """# Research Report
|
|
|
|
Main citation [1].
|
|
|
|
## Sources
|
|
|
|
[1] Real Source
|
|
URL: https://real.com/paper
|
|
|
|
## Other Sources (not formatted)
|
|
|
|
[2] This should not be formatted
|
|
URL: https://notformatted.com
|
|
|
|
Back to text [2].
|
|
|
|
## Sources Again
|
|
|
|
This section also has [3] which shouldn't format."""
|
|
|
|
formatter = CitationFormatter(mode=CitationMode.DOMAIN_HYPERLINKS)
|
|
result = formatter.format_document(content)
|
|
|
|
# Only first Sources section should be used
|
|
assert "[real.com]" in result
|
|
assert "[2]" in result # Should remain as-is
|
|
assert "[notformatted.com]" not in result
|