This repository has been archived on 2026-10-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
recoll-modern/tests/contract/test_recoll_adapter_unit.py
T

134 lines
4.6 KiB
Python

import subprocess
import sys
from pathlib import Path
from types import ModuleType, SimpleNamespace
import pytest
from recoll_modern.engine.protocol import EngineUnavailable, SearchRequest
from recoll_modern.engine.recoll import RecollEngine
def test_force_reindex_uses_argument_list(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
calls: list[list[str]] = []
def run(args: list[str], **_kwargs: object) -> None:
calls.append(args)
monkeypatch.setattr(subprocess, "run", run)
engine = RecollEngine(tmp_path)
engine.force_reindex(("/documents/odd name.txt",))
assert calls == [[
"recollindex", "-c", str(tmp_path), "-i", "-Z", "/documents/odd name.txt"
]]
def test_force_reindex_hides_process_stderr(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
def fail(_args: list[str], **_kwargs: object) -> None:
raise subprocess.CalledProcessError(1, "recollindex", stderr="private path")
monkeypatch.setattr(subprocess, "run", fail)
with pytest.raises(EngineUnavailable) as caught:
RecollEngine(tmp_path).force_reindex(("/documents/a.txt",))
assert "private" not in str(caught.value)
def test_empty_search_does_not_scroll(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
class EmptyQuery:
rowcount = 0
def execute(self, *_args: object, **_kwargs: object) -> None:
pass
def scroll(self, *_args: object) -> None:
raise AssertionError("empty result must not scroll")
def close(self) -> None:
pass
query = EmptyQuery()
db = SimpleNamespace(query=lambda: query, close=lambda: None)
monkeypatch.setattr(RecollEngine, "_connect", lambda self: db)
page = RecollEngine(tmp_path).search(SearchRequest(
"python", ("c0000000001",), 20, 0, False
))
assert page.total == 0 and page.hits == ()
def test_query_cannot_escape_collection_scope(tmp_path: Path) -> None:
with pytest.raises(ValueError, match="query"):
RecollEngine(tmp_path).search(SearchRequest(
"python) OR all OR (", ("c0000000001",), 20, 0, False
))
def test_search_uses_one_scoped_query(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
executed: list[str] = []
doc = SimpleNamespace(
getbinurl=lambda: b"file:///documents/odd name.txt",
title="Python guide", author="Ada", mtype="text/plain", fbytes="12",
fmtime="", collection="c0000000001 c0000000002", text="Python guide",
)
class Query:
rowcount = 1
def execute(self, query: str, **_kwargs: object) -> None:
executed.append(query)
def scroll(self, offset: int, mode: str) -> None:
assert (offset, mode) == (0, "absolute")
def fetchmany(self, limit: int) -> list[object]:
assert limit == 20
return [doc]
def getsnippets(self, _doc: object, **_kwargs: object) -> list[tuple[int, str, str]]:
return [(0, "Python", "Python guide")]
def close(self) -> None:
pass
db = SimpleNamespace(query=Query, close=lambda: None)
monkeypatch.setattr(RecollEngine, "_connect", lambda self: db)
page = RecollEngine(tmp_path).search(SearchRequest(
"python", ("c0000000001", "c0000000002"), 20, 0, True
))
assert executed == [
"(python) AND (collection:c0000000001 OR collection:c0000000002)"
]
assert page.hits[0].path == "/documents/odd name.txt"
assert page.hits[0].collection_ids == ("c0000000001", "c0000000002")
assert page.hits[0].text == "Python guide"
def test_extracted_text_uses_exact_path_udi(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
path = '/documents/odd "name" (draft).txt'
seen: list[str] = []
recoll_package = ModuleType("recoll")
def fake_udi(value: str) -> str:
seen.append(value)
return "udi"
recoll_package.fsudi = SimpleNamespace(fs_udi=fake_udi) # type: ignore[attr-defined]
recoll_package.rclextract = SimpleNamespace( # type: ignore[attr-defined]
Extractor=lambda _doc: SimpleNamespace(
textextract=lambda _ipath: SimpleNamespace(text="Complete text")
)
)
monkeypatch.setitem(sys.modules, "recoll", recoll_package)
db = SimpleNamespace(
getDoc=lambda udi: SimpleNamespace(
ipath="", getbinurl=lambda: path.encode()
) if udi == "udi" else None,
close=lambda: None,
)
monkeypatch.setattr(RecollEngine, "_connect", lambda self: db)
assert RecollEngine(tmp_path).extracted_text(path) == "Complete text"
assert seen == [path]