mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 00:26:26 +00:00
ci: verify PDF page counts and text layers via poppler (#145)
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from tools.verify_pdf import VerificationError, parse_page_count, run_tool, verify_pdf
|
||||
|
||||
|
||||
class ParsePageCountTests(unittest.TestCase):
|
||||
def test_parses_pdfinfo_page_count(self):
|
||||
self.assertEqual(parse_page_count("Title: Example\nPages: 2\n"), 2)
|
||||
|
||||
def test_rejects_output_without_page_count(self):
|
||||
with self.assertRaisesRegex(VerificationError, "did not contain a page count"):
|
||||
parse_page_count("Title: Example\n")
|
||||
|
||||
|
||||
class VerifyPdfTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp_dir = tempfile.TemporaryDirectory()
|
||||
self.pdf = Path(self.temp_dir.name) / "example.pdf"
|
||||
self.pdf.touch()
|
||||
|
||||
def tearDown(self):
|
||||
self.temp_dir.cleanup()
|
||||
|
||||
@patch("tools.verify_pdf.run_tool")
|
||||
def test_accepts_expected_pages_and_text(self, mock_run_tool):
|
||||
mock_run_tool.side_effect = [
|
||||
"Pages: 2\n",
|
||||
"Professional\nExperience [your.email@example.com]\n",
|
||||
]
|
||||
|
||||
verify_pdf(
|
||||
self.pdf,
|
||||
expected_pages=2,
|
||||
min_chars=20,
|
||||
required_text=("Professional Experience", "[your.email@example.com]"),
|
||||
)
|
||||
|
||||
@patch("tools.verify_pdf.run_tool")
|
||||
def test_rejects_wrong_page_count(self, mock_run_tool):
|
||||
mock_run_tool.return_value = "Pages: 3\n"
|
||||
|
||||
with self.assertRaisesRegex(VerificationError, "expected 2 page.*found 3"):
|
||||
verify_pdf(self.pdf, expected_pages=2)
|
||||
|
||||
@patch("tools.verify_pdf.run_tool")
|
||||
def test_rejects_too_little_extractable_text(self, mock_run_tool):
|
||||
mock_run_tool.return_value = "short"
|
||||
|
||||
with self.assertRaisesRegex(VerificationError, "expected at least 20"):
|
||||
verify_pdf(self.pdf, min_chars=20)
|
||||
|
||||
@patch("tools.verify_pdf.run_tool")
|
||||
def test_rejects_missing_required_text(self, mock_run_tool):
|
||||
mock_run_tool.return_value = "Readable text, but not the expected section."
|
||||
|
||||
with self.assertRaisesRegex(VerificationError, "Professional Experience"):
|
||||
verify_pdf(self.pdf, required_text=("Professional Experience",))
|
||||
|
||||
def test_rejects_missing_pdf(self):
|
||||
with self.assertRaisesRegex(VerificationError, "PDF does not exist"):
|
||||
verify_pdf(Path(self.temp_dir.name) / "missing.pdf")
|
||||
|
||||
|
||||
class RunToolTests(unittest.TestCase):
|
||||
@patch("tools.verify_pdf.subprocess.run", side_effect=FileNotFoundError)
|
||||
def test_reports_missing_poppler_command(self, _mock_run):
|
||||
with self.assertRaisesRegex(VerificationError, "install poppler-utils"):
|
||||
run_tool(["pdftotext", "example.pdf", "-"])
|
||||
|
||||
@patch("tools.verify_pdf.subprocess.run")
|
||||
def test_reports_unreadable_pdf(self, mock_run):
|
||||
mock_run.side_effect = subprocess.CalledProcessError(
|
||||
1, ["pdfinfo", "example.pdf"], stderr="invalid PDF"
|
||||
)
|
||||
|
||||
with self.assertRaisesRegex(VerificationError, "invalid PDF"):
|
||||
run_tool(["pdfinfo", "example.pdf"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user