Recorrection GUI step ; LaTeX issues debugging
This commit is contained in:
1 parent
2d0f7a219f
commit
48602c24f1
12 files changed
+306
-8
No files matched your search
@@ -0,0 +1,58 @@
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from subprocess import CompletedProcess
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from copienator.commands import annotating
|
||||
|
||||
|
||||
class AnnotationLatexErrorTests(unittest.TestCase):
|
||||
def test_failure_preserves_source_and_log_and_explains_recovery(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
diagnostics = Path(directory) / "diagnostics"
|
||||
diagnostics.mkdir()
|
||||
|
||||
def compile_latex(command, **kwargs):
|
||||
Path(kwargs["cwd"], "text.log").write_bytes(
|
||||
b"preamble\n! Missing \\endcsname inserted.\nl.12 \\end{document}\n\xff"
|
||||
)
|
||||
return CompletedProcess(command, 1, stdout=b"compiler output\xff")
|
||||
|
||||
# Patch only the retained diagnostics directory, not TemporaryDirectory.
|
||||
original_mkdtemp = tempfile.mkdtemp
|
||||
|
||||
def make_directory(*args, **kwargs):
|
||||
if kwargs.get("prefix") == "copienator-latex-error-":
|
||||
return str(diagnostics)
|
||||
return original_mkdtemp(*args, **kwargs)
|
||||
|
||||
with patch.object(annotating.subprocess, "run", side_effect=compile_latex), patch.object(
|
||||
annotating.tempfile, "mkdtemp", side_effect=make_directory
|
||||
):
|
||||
with self.assertRaises(annotating.AnnotationLatexError) as caught:
|
||||
annotating.render_real_latex_text(r"Antislash \.", 400)
|
||||
message = str(caught.exception)
|
||||
for expected in ("code 1", r"Antislash \.", "Missing", "correction.json", "relancez cette étape", str(diagnostics)):
|
||||
self.assertIn(expected, message)
|
||||
self.assertIn(r"Antislash \.", (diagnostics / "text.tex").read_text())
|
||||
self.assertTrue((diagnostics / "text.log").exists())
|
||||
self.assertTrue((diagnostics / "compiler-output.txt").exists())
|
||||
|
||||
def test_comment_error_identifies_copy_label_and_correction_file(self):
|
||||
for box in (None, [0, 0, 20, 20]):
|
||||
with self.subTest(box=box), patch.object(
|
||||
annotating, "render_score_text", return_value=Image.new("RGBA", (200, 40))
|
||||
):
|
||||
with self.assertRaises(annotating.AnnotationLatexError) as caught:
|
||||
annotating.compose_label_image(
|
||||
Image.new("RGB", (800, 200)), "I)7)",
|
||||
{"feedback": [{"text": "Bad comment", "box_2d": box}]}, 0,
|
||||
render_fn=Mock(side_effect=annotating.AnnotationLatexError("Bad comment")),
|
||||
source_pdf=Path("/exam/Copies/Copie39/I)7).pdf"),
|
||||
)
|
||||
message = str(caught.exception)
|
||||
for expected in ("Copie39", "I)7)", "/exam/correction.json", "Bad comment"):
|
||||
self.assertIn(expected, message)
|
||||
@@ -214,6 +214,49 @@ class GuiConvenienceTests(unittest.TestCase):
|
||||
self.assertNotIn("overwrite", self.app.arg_vars)
|
||||
self.assertIn("--refaire", self.app._make_command())
|
||||
|
||||
def test_optional_recorrection_opens_examples_and_returns_to_correction(self):
|
||||
from copienator import read_json
|
||||
ids = [step.id for step in self.app.steps]
|
||||
self.assertEqual(ids[ids.index("manual_resolution") + 1], "prepare_recorrection")
|
||||
copies = self.evaluation / "Copies"
|
||||
copies.mkdir()
|
||||
(copies / "Copie46.pdf").touch()
|
||||
(self.evaluation / "labels").write_text("II)9)\n")
|
||||
self.app.tree.selection_set("prepare_recorrection")
|
||||
self.app.update()
|
||||
with patch("copienator_gui.app.open_path") as opened:
|
||||
self.app.edit_recorrection_button.invoke()
|
||||
path = self.evaluation / "refaire.json"
|
||||
opened.assert_called_once_with(path)
|
||||
self.assertEqual(read_json(path), [])
|
||||
path.write_text(path.read_text().replace("\n[]\n", '\n[["Copie46", []]]\n'))
|
||||
with patch.object(self.app.runner, "start") as start:
|
||||
self.app.run_button.invoke()
|
||||
self.app.update()
|
||||
start.assert_not_called()
|
||||
self.assertEqual(self.app.state_store.step("prepare_recorrection")["status"], "success")
|
||||
self.assertEqual(self.app.current_step.id, "correction")
|
||||
self.assertEqual(self.app.variant_var.get(), "refaire")
|
||||
self.assertIn("--refaire", self.app._make_command())
|
||||
self.assertNotIn("--overwrite", self.app._make_command())
|
||||
|
||||
def test_ignoring_optional_recorrection_continues_without_creating_file(self):
|
||||
self.app.tree.selection_set("prepare_recorrection")
|
||||
self.app.update()
|
||||
self.app._skip_step()
|
||||
self.app.update()
|
||||
self.assertEqual(self.app.current_step.id, "post_correction")
|
||||
self.assertEqual(self.app.state_store.step("prepare_recorrection")["status"], "skipped")
|
||||
self.assertFalse((self.evaluation / "refaire.json").exists())
|
||||
|
||||
def test_optional_recorrection_requires_a_saved_selection(self):
|
||||
self.app.tree.selection_set("prepare_recorrection")
|
||||
self.app.update()
|
||||
with patch("copienator_gui.app.messagebox.showerror") as error:
|
||||
self.app.run_button.invoke()
|
||||
error.assert_called_once()
|
||||
self.assertEqual(self.app.current_step.id, "prepare_recorrection")
|
||||
|
||||
def test_giving_names_waits_for_explicit_manual_completion(self):
|
||||
return_dir = self.evaluation / "A Rendre" / "Student (01)"
|
||||
return_dir.mkdir(parents=True)
|
||||
@@ -560,6 +603,25 @@ class GuiConvenienceTests(unittest.TestCase):
|
||||
self.assertIn("Cibler la copie sélectionnée", controls)
|
||||
self.assertIn("Cibler tout le dossier", controls)
|
||||
|
||||
def test_answer_splitting_waits_for_target_and_can_select_one_copy(self):
|
||||
copies = self.evaluation / "Copies"
|
||||
copies.mkdir()
|
||||
for name in ("Copie01.pdf", "Copie46.pdf"):
|
||||
(copies / name).touch()
|
||||
with patch.object(self.app, "_run_current_step") as run:
|
||||
self.app.tree.selection_set("splitting")
|
||||
self.app.update()
|
||||
run.assert_not_called()
|
||||
self.assertIn("Copie46.pdf", self.app.copy_paths)
|
||||
self.app.copy_var.set("Copie46.pdf")
|
||||
self.app._target_selected_copy()
|
||||
command = self.app._make_command()
|
||||
self.assertIn("split-answers", command)
|
||||
self.assertEqual(Path(command[5]), copies / "Copie46.pdf")
|
||||
self.app._target_all_pages()
|
||||
command = self.app._make_command()
|
||||
self.assertEqual((self.repository / command[5]).resolve(), self.evaluation)
|
||||
|
||||
def test_label_review_can_show_and_target_one_copy(self):
|
||||
copies = self.evaluation / "Copies"
|
||||
copies.mkdir()
|
||||
|
||||
@@ -2378,7 +2378,7 @@ class WorkflowTests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(
|
||||
auto_start,
|
||||
{"crop_blank_margins", "splitting", "crop_exercise_bottoms", "grouping"},
|
||||
{"crop_blank_margins", "crop_exercise_bottoms", "grouping"},
|
||||
)
|
||||
self.assertEqual(
|
||||
skip_for_live, {"submit_batches", "batch_status", "fetch_batches"}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from copienator import read_json
|
||||
from copienator_gui.recorrection import prepare_selection_file
|
||||
|
||||
|
||||
class RecorrectionFileTests(unittest.TestCase):
|
||||
def test_examples_are_inactive_and_opening_preserves_selection(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
path = prepare_selection_file(root)
|
||||
self.assertEqual(read_json(path), [])
|
||||
self.assertIn('// Une copie entière', path.read_text())
|
||||
selection = [["Copie46", ["II)9)"]]]
|
||||
path.write_text(json.dumps(selection))
|
||||
prepare_selection_file(root)
|
||||
self.assertEqual(read_json(path), selection)
|
||||
before = path.read_bytes()
|
||||
prepare_selection_file(root)
|
||||
self.assertEqual(path.read_bytes(), before)
|
||||
|
||||
def test_comments_do_not_affect_strings_or_other_json_files(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
path = root / "refaire.json"
|
||||
path.write_text('// Example\n[["Copie01", ["a//b"]]]\n')
|
||||
self.assertEqual(read_json(path), [["Copie01", ["a//b"]]])
|
||||
other = root / "correction.json"
|
||||
other.write_text(path.read_text())
|
||||
with self.assertRaises(json.JSONDecodeError):
|
||||
read_json(other)
|
||||
Reference in new issue
Block a user