Files
2026-07-13 13:12:33 +08:00

110 lines
3.3 KiB
Python

"""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]