"""pdf-toolkit skill — load, eligibility, and merge→split→extract round-trip.""" from __future__ import annotations import sys from pathlib import Path import pytest from opensquilla.skills.eligibility import EligibilityContext, check_eligibility from opensquilla.skills.loader import SkillLoader ROOT = Path(__file__).resolve().parents[1] BUNDLED = ROOT / "src" / "opensquilla" / "skills" / "bundled" SCRIPTS = BUNDLED / "pdf-toolkit" / "scripts" def _spec() -> object: return SkillLoader(bundled_dir=BUNDLED).get_by_name("pdf-toolkit") def test_skill_loads() -> None: spec = _spec() assert spec is not None assert spec.name == "pdf-toolkit" description = spec.description.lower() assert "nano-pdf" in description, ( "description must explicitly distinguish from sibling nano-pdf skill" ) def test_eligibility_with_python(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr( "opensquilla.skills.eligibility.shutil.which", lambda name: "/usr/bin/python3" if name in {"python", "python3"} else None, ) spec = _spec() assert spec is not None assert check_eligibility(spec, EligibilityContext.auto()) def _make_one_page_pdf(path: Path, label: str) -> None: from reportlab.lib.pagesizes import LETTER from reportlab.pdfgen import canvas c = canvas.Canvas(str(path), pagesize=LETTER) c.setFont("Helvetica", 14) c.drawString(72, 720, label) c.showPage() c.save() def test_merge_split_extract_round_trip(tmp_path: Path) -> None: sys.path.insert(0, str(SCRIPTS)) try: import extract # type: ignore[import-not-found] import merge # type: ignore[import-not-found] import split # type: ignore[import-not-found] finally: sys.path.pop(0) a = tmp_path / "a.pdf" b = tmp_path / "b.pdf" _make_one_page_pdf(a, "ALPHA") _make_one_page_pdf(b, "BRAVO") combined = tmp_path / "combined.pdf" written = merge.merge([{"file": str(a)}, {"file": str(b)}], combined) assert written == 2 assert combined.exists() out_dir = tmp_path / "split_out" parts = split.split(combined, "1,2", out_dir) assert len(parts) == 2 payload = extract.extract(combined, tables_strategy=None) assert payload["pages"] == 2 page_texts = [item["content"] for item in payload["text"]] full_text = "\n".join(page_texts) assert "ALPHA" in full_text assert "BRAVO" in full_text def test_split_range_parsing() -> None: sys.path.insert(0, str(SCRIPTS)) try: import split # type: ignore[import-not-found] finally: sys.path.pop(0) assert split.split_ranges("1-3") == [[1, 2, 3]] assert split.split_ranges("1,3,5") == [[1], [3], [5]] assert split.split_ranges("1-2,4-5") == [[1, 2], [4, 5]] # Reverse range gets normalized. assert split.split_ranges("5-3") == [[3, 4, 5]] def test_merge_range_parsing() -> None: sys.path.insert(0, str(SCRIPTS)) try: import merge # type: ignore[import-not-found] finally: sys.path.pop(0) assert merge.parse_ranges(None, 4) == [1, 2, 3, 4] assert merge.parse_ranges("1,3", 4) == [1, 3] assert merge.parse_ranges("1-3", 5) == [1, 2, 3] # Out-of-range pages are filtered. assert merge.parse_ranges("1,99", 4) == [1]