feat(scan): support iX1600 duplex scanning on Linux
This commit is contained in:
93
agents/fedeo-device-agent/tests/scan_document_test.py
Normal file
93
agents/fedeo-device-agent/tests/scan_document_test.py
Normal file
@@ -0,0 +1,93 @@
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
from PIL import Image, PdfParser
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
|
||||
from scan_document import create_document
|
||||
|
||||
|
||||
class ScanDocumentTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.root = Path(self.temp.name)
|
||||
|
||||
def pages(self, count=4):
|
||||
paths = []
|
||||
for index in range(1, count + 1):
|
||||
target = self.root / f"page-{index:06}.png"
|
||||
# Distinct geometry identifies every front/back page and its order.
|
||||
with Image.new("RGB", (100 + index, 200 + index), "white") as image:
|
||||
image.save(target)
|
||||
paths.append(target)
|
||||
return paths
|
||||
|
||||
def assert_pdf(self, output, count, resolution=300):
|
||||
with PdfParser.PdfParser(filename=str(output)) as pdf:
|
||||
self.assertEqual(len(pdf.pages), count)
|
||||
for index, reference in enumerate(pdf.pages, 1):
|
||||
page = pdf.read_indirect(reference)
|
||||
box = page[b"MediaBox"]
|
||||
self.assertAlmostEqual(box[2], (100 + index) * 72 / resolution, places=4)
|
||||
self.assertAlmostEqual(box[3], (200 + index) * 72 / resolution, places=4)
|
||||
|
||||
def test_twelve_pages_keep_front_back_order_blank_pages_and_scan_resolution(self):
|
||||
output = self.root / "scan.pdf"
|
||||
result = create_document(self.pages(12), output, 150)
|
||||
self.assertEqual(result, {"pageCount": 12, "warnings": []})
|
||||
self.assert_pdf(output, 12, 150)
|
||||
|
||||
def test_missing_opencv_still_creates_complete_pdf(self):
|
||||
output = self.root / "scan.pdf"
|
||||
with patch.dict(sys.modules, {"opencv_postprocess": None}):
|
||||
result = create_document(self.pages(), output, 300, use_postprocess=True)
|
||||
self.assertEqual(len(result["warnings"]), 1)
|
||||
self.assert_pdf(output, 4)
|
||||
|
||||
def test_failed_correction_falls_back_per_page_without_losing_sides(self):
|
||||
def correct(source, target, profile):
|
||||
if source.name.endswith("000002.png"):
|
||||
raise RuntimeError("correction failed")
|
||||
target.write_bytes(source.read_bytes())
|
||||
|
||||
output = self.root / "scan.pdf"
|
||||
with patch.dict(sys.modules, {"opencv_postprocess": SimpleNamespace(postprocess=correct)}):
|
||||
result = create_document(self.pages(), output, 300, use_postprocess=True)
|
||||
self.assertEqual(len(result["warnings"]), 1)
|
||||
self.assertIn("Seite 2", result["warnings"][0])
|
||||
self.assert_pdf(output, 4)
|
||||
|
||||
def test_strict_mode_does_not_silently_skip_missing_correction(self):
|
||||
output = self.root / "scan.pdf"
|
||||
with patch.dict(sys.modules, {"opencv_postprocess": None}):
|
||||
with self.assertRaises(ImportError):
|
||||
create_document(self.pages(), output, 300, use_postprocess=True, strict=True)
|
||||
self.assertFalse(output.exists())
|
||||
|
||||
def test_corrupt_page_never_publishes_partial_pdf(self):
|
||||
pages = self.pages()
|
||||
pages[2].write_bytes(b"corrupt")
|
||||
output = self.root / "scan.pdf"
|
||||
with self.assertRaises(OSError):
|
||||
create_document(pages, output, 300)
|
||||
self.assertFalse(output.exists())
|
||||
self.assertFalse((self.root / "scan.pdf.partial").exists())
|
||||
self.assertTrue(all(page.exists() for page in pages))
|
||||
|
||||
def test_single_page_png_and_tiff_remain_supported(self):
|
||||
pages = self.pages(1)
|
||||
for extension in ["png", "tiff"]:
|
||||
output = self.root / f"scan.{extension}"
|
||||
create_document(pages, output, 150)
|
||||
with Image.open(output) as image:
|
||||
self.assertEqual(image.size, (101, 201))
|
||||
self.assertAlmostEqual(image.info["dpi"][0], 150, delta=0.1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user