Files
Copies/tests/test_pdf_supplements.py

111 lines
4.4 KiB
Python

import tempfile
import unittest
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch
from PIL import Image
from reportlab.pdfgen import canvas
from copienator.commands.reading_grouped_annotations import (
context_content_key, get_extra_pdfs_as_images, save_paginated_pdf,
)
class PdfSupplementTests(unittest.TestCase):
def setUp(self):
temporary = tempfile.TemporaryDirectory()
self.addCleanup(temporary.cleanup)
self.root = Path(temporary.name)
(self.root / "Text2").mkdir()
(self.root / "Sol2").mkdir()
self.labels = ["Q1", "Q2", "Q3"]
self.rendered = []
def render(path):
self.rendered.append(Path(path).name)
return Image.new("RGB", (100, 30), "white"), 30, 100
self.renderer = SimpleNamespace(make_base_image=render)
def pdf(self, folder, name, text):
path = self.root / folder / name
document = canvas.Canvas(str(path))
document.drawString(20, 800, text)
document.save()
return path
def extras(self, label, seen):
return get_extra_pdfs_as_images(
self.root, label, self.renderer, self.labels, seen_contexts=seen,
)
def test_content_deduplication_across_ranges_and_copy_reset(self):
self.pdf("Text2", "CTXT Q1 -> Q2.pdf", "Bob collects coupons: N >= 1")
self.pdf("Text2", "CTXT Q2 -> Q3.pdf", "Bob collects coupons: N >= 1")
self.pdf("Text2", "CTXT Q2 -> Q2.pdf", "Bob collects coupons: N >= 2")
seen = set()
self.assertEqual(len(self.extras("Q1", seen)), 1)
self.assertEqual(len(self.extras("Q2", seen)), 1)
self.assertEqual(len(self.extras("Q3", seen)), 0)
self.assertEqual(len(seen), 2)
self.assertEqual(len(self.extras("Q3", set())), 1)
def test_first_retained_question_gets_context_and_semantic_borders(self):
self.pdf("Text2", "CTXT Q1 -> Q3.pdf", "Context")
self.pdf("Text2", "CTXT Q2 -> Q3.pdf", "Other context")
self.pdf("Text2", "Q2.pdf", "Question")
self.pdf("Sol2", "Q2.pdf", "Solution")
# Q1 was filtered out; it never consumes the shared context.
images = self.extras("Q2", set())
self.assertEqual([i.getpixel((0, 0)) for i in images],
[(255, 255, 255), (255, 255, 255), (0, 0, 0), (0, 0, 255)])
self.assertTrue(all(i.getpixel((50, 15)) == (255, 255, 255) for i in images))
def test_missing_question_does_not_shift_solution_border(self):
self.pdf("Text2", "CTXT Q1 -> Q3.pdf", "Context")
self.pdf("Sol2", "Q2.pdf", "Solution")
images = self.extras("Q2", set())
self.assertEqual([i.getpixel((0, 0)) for i in images],
[(255, 255, 255), (0, 0, 255)])
def test_unrendered_context_is_not_consumed(self):
self.pdf("Text2", "CTXT Q1 -> Q3.pdf", "Context")
seen = set()
with patch.object(self.renderer, "make_base_image", return_value=(None, 0, 0)):
self.assertEqual(self.extras("Q1", seen), [])
self.assertFalse(seen)
self.assertEqual(len(self.extras("Q2", seen)), 1)
def test_missing_solution_does_not_shift_border_to_student_answer(self):
self.pdf("Text2", "Q2.pdf", "Question")
images = self.extras("Q2", set())
answer = Image.new("RGB", (100, 200), "white")
captured = []
def save(page, *args, **kwargs):
captured.extend([page.copy(), *kwargs['append_images']])
with patch.object(Image.Image, "save", save):
save_paginated_pdf([images + [answer], [answer]], self.root / "out.pdf")
self.assertEqual(len(captured), 2)
self.assertEqual(captured[0].getpixel((11, 7)), (0, 0, 0))
self.assertEqual(captured[0].getpixel((11, 37)), (255, 255, 255))
self.assertEqual(captured[1].getpixel((11, 7)), (255, 255, 255))
self.assertEqual(answer.getpixel((0, 0)), (255, 255, 255))
def test_empty_extracted_text_does_not_merge_distinct_contexts(self):
paths = []
for name, color in [("a.pdf", "red"), ("b.pdf", "blue")]:
path = self.root / name
document = canvas.Canvas(str(path))
document.setFillColor(color)
document.rect(20, 20, 100, 100, fill=1)
document.save()
paths.append(path)
self.assertNotEqual(context_content_key(paths[0]), context_content_key(paths[1]))
if __name__ == "__main__":
unittest.main()