qalmsw / tests /test_semantic_scholar.py
pebaryan
Semantic Scholar backend, JSON output, image checker, batch mode
a438ef8
Raw
History Blame Contribute Delete
3.44 kB
"""Tests for Semantic Scholar retrieval module."""
from unittest.mock import patch
from qalmsw.retrieval import ScholarResult, search_by_title
def _mock_response(data: list[dict]) -> dict:
return {"data": data}
def _paper(
title: str = "Attention Is All You Need",
authors: list[str] | None = None,
year: int | None = 2017,
abstract: str = "We propose the Transformer architecture.",
arxiv_id: str = "1706.03762",
url: str = "https://api.semanticscholar.org/CorpusID:1",
) -> dict:
return {
"title": title,
"authors": [{"name": a} for a in (authors or ["Ashish Vaswani", "Noam Shazeer"])],
"year": year,
"abstract": abstract,
"externalIds": {"ArXiv": arxiv_id} if arxiv_id else {},
"url": url,
}
def _mock_urlopen(json_data: dict):
"""Return a mock urlopen context manager."""
import json as _json
from unittest.mock import MagicMock
cm = MagicMock()
cm.__enter__.return_value.read.return_value = _json.dumps(json_data).encode("utf-8")
return cm
def test_search_by_title_returns_first_match():
data = _mock_response([_paper()])
with patch("qalmsw.retrieval.semantic_scholar.urllib.request.urlopen",
return_value=_mock_urlopen(data)):
result = search_by_title("attention transformer")
assert isinstance(result, ScholarResult)
assert result.title == "Attention Is All You Need"
assert result.authors == ["Ashish Vaswani", "Noam Shazeer"]
assert result.year == 2017
assert "Transformer" in result.abstract
assert "semanticscholar" in (result.url or "")
def test_search_by_title_returns_none_when_no_results():
data = _mock_response([])
with patch("qalmsw.retrieval.semantic_scholar.urllib.request.urlopen",
return_value=_mock_urlopen(data)):
assert search_by_title("no such paper xyzzy") is None
def test_search_by_title_returns_none_on_http_error():
import urllib.error
def _raise(*args, **kwargs):
raise urllib.error.HTTPError(
"http://example.com", 429, "Too Many", {}, None
)
with patch("qalmsw.retrieval.semantic_scholar.urllib.request.urlopen", _raise):
assert search_by_title("any title") is None
def test_missing_fields_produce_safe_defaults():
data = _mock_response([
_paper(
title="", authors=None, year=None,
abstract="", arxiv_id="", url="",
)
])
with patch("qalmsw.retrieval.semantic_scholar.urllib.request.urlopen",
return_value=_mock_urlopen(data)):
result = search_by_title("x")
assert result is None # empty title → None
def test_empty_title_returns_none():
data = _mock_response([_paper(title="", authors=None)])
with patch("qalmsw.retrieval.semantic_scholar.urllib.request.urlopen",
return_value=_mock_urlopen(data)):
assert search_by_title("x") is None
def test_exact_title_match_is_preferred():
data = _mock_response([
_paper(title="Some Related Work", year=2020),
_paper(title="Attention Is All You Need", year=2017),
])
with patch("qalmsw.retrieval.semantic_scholar.urllib.request.urlopen",
return_value=_mock_urlopen(data)):
result = search_by_title("Attention Is All You Need")
assert result is not None
assert result.title == "Attention Is All You Need"
assert result.year == 2017