import tempfile import unittest from pathlib import Path from unittest.mock import patch from PIL import Image from copienator import atomic_write_json, read_json from copienator.commands import annotating_by_label as grouped from copienator.utils import natural_key class GroupedNamingTests(unittest.TestCase): def test_dsi_question_groups_have_short_unique_ordered_prefixes(self): groups = [ ["Ex 1", "Ex 2", "Ex 3"], ["Ex 4 : 1)", "Ex 4 : 2)"], ["I)1)", "I)2)"], ["I)3)", "I)4)"], ["I)5)", "I)6)", "I)7)"], ["I)8)", "I)9)"], ["I)10)", "I)11)", "I)12)"], ["I)13)"], ["I)14)", "I)15)", "I)16)"], ["II)1)", "II)2)"], ["II)3)a)", "II)3)b)"], ["II)4)", "II)5)", "II)6)", "II)7)"], ["II)8)", "II)9)"], ["II)10)"], ] named = grouped._unique_prefixes(groups) prefixes = [prefix for prefix, _labels in named] self.assertEqual(len(prefixes), len(set(prefixes))) self.assertEqual(prefixes, sorted(prefixes, key=natural_key)) self.assertEqual(prefixes, [ "Ex", "Ex-2", "I)", "I)-2", "I)-3", "I)-4", "I)-5", "I)-6", "I)-7", "II)", "II)-2", "II)-3", "II)-4", "II)-5", ]) self.assertEqual([labels for _prefix, labels in named], groups) def test_resume_preserves_legacy_names_and_appends_only_missing_answers(self): with tempfile.TemporaryDirectory() as temporary: output = Path(temporary) # The old naming bug put distinct question groups under I)-2. for number, label in enumerate(["I)3)", "I)10)", "II)1)"], start=1): folder = output / f"I)-2 G{number}" folder.mkdir() atomic_write_json(folder / "bnote.json", { "images": [{"id": "01", "label": label}], }) (folder / "Concat.pdf").write_bytes(b"reviewed PDF") before = {p: p.read_bytes() for p in output.rglob("*") if p.is_file()} groups = [["I)1)", "I)2)"], ["I)3)", "I)4)"], ["I)10)", "I)11)"], ["II)1)", "II)2)"]] data = {"01": {label: {} for label in ["I)3)", "I)10)", "II)1)"]}} with patch.object(grouped, "render_item") as render: self.assertEqual(grouped._generate_groups( output, data, groups, resume=True, ), (0, False)) render.assert_not_called() self.assertEqual(before, { p: p.read_bytes() for p in output.rglob("*") if p.is_file() }) data["02"] = {"I)3)": {}} with patch.object(grouped, "render_item", return_value=( "02", "I)3)", Image.new("RGB", (100, 100), "white"), 0, [], )) as render: self.assertEqual(grouped._generate_groups( output, data, groups, resume=True, ), (1, False)) render.assert_called_once_with(("02", "I)3)", {})) self.assertEqual(read_json(output / "I)-2 G4/bnote.json")["images"][0]["id"], "02") for path, content in before.items(): self.assertEqual(path.read_bytes(), content) if __name__ == "__main__": unittest.main()