Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions qubespdfconverter/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,21 @@ async def render_page(self, page, prefix):
return rep


RENDERERS = {
"pdf": PdfRenderer,
}


def create_renderer(name, path, password=b"", resolution=RESOLUTION):
"""Create a renderer for the requested converter type."""
try:
renderer_cls = RENDERERS[name]
except KeyError as exc:
raise ValueError(f"Unsupported renderer: {name}") from exc

return renderer_cls(path, password, resolution)


class Representation:
"""Umbrella object for a file's initial and final representations

Expand Down Expand Up @@ -220,10 +235,9 @@ class BatchEntry:

class BaseFile:
"""Unsanitized file"""
def __init__(self, path, password=b""):
def __init__(self, path, renderer):
self.path = path
self.password = password
self.renderer = PdfRenderer(path, password, args.resolution)
self.renderer = renderer
self.pagenums = 0
self.batch = None

Expand Down Expand Up @@ -333,7 +347,8 @@ def main():
with TemporaryDirectory(prefix="qvm-sanitize") as tmpdir:
pdf_path = Path(tmpdir, "original")
pdf_path.write_bytes(data)
base = BaseFile(pdf_path, password)
renderer = create_renderer("pdf", pdf_path, password, args.resolution)
base = BaseFile(pdf_path, renderer)

try:
asyncio.run(base.sanitize())
Expand Down
28 changes: 25 additions & 3 deletions qubespdfconverter/tests/test_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from pathlib import Path
from unittest import mock

from qubespdfconverter.server import BaseFile, PdfRenderer
from qubespdfconverter.server import BaseFile, PdfRenderer, create_renderer


class TC_ServerPassword(unittest.IsolatedAsyncioTestCase):
Expand All @@ -20,7 +20,8 @@ class TC_ServerPassword(unittest.IsolatedAsyncioTestCase):
def test_pagenums_includes_password_flags(self):
"""pdfinfo receives -opw/-upw when a password is provided."""
with tempfile.NamedTemporaryFile(suffix=".pdf") as f:
base = BaseFile(Path(f.name), password=b"secret")
renderer = PdfRenderer(Path(f.name), password=b"secret")
base = BaseFile(Path(f.name), renderer)

mock_result = mock.Mock()
mock_result.stdout = b"Pages: 3\n"
Expand All @@ -36,7 +37,8 @@ def test_pagenums_includes_password_flags(self):
def test_pagenums_omits_password_flags_when_empty(self):
"""pdfinfo does not receive password flags when password is empty."""
with tempfile.NamedTemporaryFile(suffix=".pdf") as f:
base = BaseFile(Path(f.name), password=b"")
renderer = PdfRenderer(Path(f.name), password=b"")
base = BaseFile(Path(f.name), renderer)

mock_result = mock.Mock()
mock_result.stdout = b"Pages: 2\n"
Expand Down Expand Up @@ -91,6 +93,26 @@ async def test_create_page_image_omits_password_flags_when_empty(self):
self.assertNotIn("-opw", cmd)
self.assertNotIn("-upw", cmd)

def test_create_renderer_returns_pdf_renderer(self):
"""The server dispatch table creates the PDF renderer."""
with tempfile.NamedTemporaryFile(suffix=".pdf") as f:
renderer = create_renderer(
"pdf",
Path(f.name),
password=b"secret",
resolution=200,
)

self.assertIsInstance(renderer, PdfRenderer)
self.assertEqual(renderer.password, b"secret")
self.assertEqual(renderer.resolution, "200")

def test_create_renderer_rejects_unknown_type(self):
"""Unknown renderer names fail before any conversion starts."""
with tempfile.NamedTemporaryFile(suffix=".pdf") as f:
with self.assertRaises(ValueError):
create_renderer("office", Path(f.name))


class TC_ServerBackwardCompat(unittest.TestCase):
"""Tests for backward-compatible stdin parsing in main()."""
Expand Down