"""Tests for CLI batch mode and retrieval backend switching.""" import json from pathlib import Path from typer.testing import CliRunner from qalmsw.cli import app from qalmsw.retrieval import search_by_title, set_backend from qalmsw.retrieval.scholar import search_by_title as gs_search from qalmsw.retrieval.semantic_scholar import search_by_title as ss_search runner = CliRunner() def test_default_backend_is_semantic_scholar(): """Module-level search_by_title should point to Semantic Scholar by default.""" assert search_by_title is ss_search def test_set_backend_google_scholar(): """Switching to google-scholar patches the module-level function.""" import qalmsw.retrieval as mod original = mod.search_by_title set_backend("google-scholar") try: assert mod.search_by_title is gs_search finally: # Restore set_backend("semantic-scholar") assert mod.search_by_title is original def test_set_backend_semantic_scholar(): """Switching back to semantic-scholar restores the original.""" import qalmsw.retrieval as mod set_backend("google-scholar") set_backend("semantic-scholar") assert mod.search_by_title is ss_search def test_set_backend_unknown_raises(): """Unknown backend name raises ValueError.""" import pytest with pytest.raises(ValueError, match="Unknown retrieval backend"): set_backend("bing") def test_resolve_files_single(tmp_path: Path): """Single existing .tex file is returned as-is.""" tex = tmp_path / "paper.tex" tex.write_text(r"\documentclass{article}\begin{document}hello\end{document}") from qalmsw.cli import _resolve_files resolved = _resolve_files([tex]) assert len(resolved) == 1 assert resolved[0] == tex def test_resolve_files_glob(tmp_path: Path): """Glob pattern expands to matching .tex files.""" (tmp_path / "ch1.tex").write_text("chapter 1") (tmp_path / "ch2.tex").write_text("chapter 2") (tmp_path / "notes.txt").write_text("not a tex file") from qalmsw.cli import _resolve_files resolved = _resolve_files([tmp_path / "ch*.tex"]) assert len(resolved) == 2 names = {f.name for f in resolved} assert names == {"ch1.tex", "ch2.tex"} def test_resolve_files_no_match(tmp_path: Path): """Glob with no matches returns empty list.""" from qalmsw.cli import _resolve_files resolved = _resolve_files([tmp_path / "nonexistent*.tex"]) assert resolved == [] def test_json_output_is_parseable_without_status_lines(tmp_path: Path): """--json should emit only JSON so CI tools can parse stdout.""" tex = tmp_path / "paper.tex" tex.write_text(r"\documentclass{article}\begin{document}Plain text.\end{document}") result = runner.invoke( app, [ "check", "--skip-grammar", "--skip-math", "--skip-reviewer", "--json", str(tex), ], ) assert result.exit_code == 0 payload = json.loads(result.stdout) assert payload["file"] == str(tex) assert payload["findings"] == [] def test_json_output_batches_multiple_files(tmp_path: Path): """Multi-file --json should still be one parseable JSON document.""" tex1 = tmp_path / "a.tex" tex2 = tmp_path / "b.tex" tex1.write_text(r"\documentclass{article}\begin{document}A.\end{document}") tex2.write_text(r"\documentclass{article}\begin{document}B.\end{document}") result = runner.invoke( app, [ "check", "--skip-grammar", "--skip-math", "--skip-reviewer", "--json", str(tex1), str(tex2), ], ) assert result.exit_code == 0 payload = json.loads(result.stdout) assert payload["total_files"] == 2 assert [file_payload["file"] for file_payload in payload["files"]] == [ str(tex1), str(tex2), ]