50 lines
2.9 KiB
Python
50 lines
2.9 KiB
Python
import json
|
|
import unittest
|
|
|
|
from copienator.latex_json import repair_latex_json, normalize_literal_newlines
|
|
from copienator.commands.gemini_for_enonce import ExamQuestions, ExamSolutions, ExamContext, GroupRubrics
|
|
|
|
|
|
class LatexJsonTests(unittest.TestCase):
|
|
def test_literal_newlines_preserve_tex_commands_and_row_breaks(self):
|
|
content = r"Paragraph\n\n Next $\neq \notin \newline$ \\ next \\\n row"
|
|
expected = "Paragraph\n\n Next " + r"$\neq \notin \newline$ \\ next \\" + "\n row"
|
|
self.assertEqual(normalize_literal_newlines(content), expected)
|
|
self.assertEqual(normalize_literal_newlines(expected), expected)
|
|
raw = json.dumps({'solutions': [{'label': '1)', 'solution_content': content}]})
|
|
parsed = ExamSolutions.model_validate_json(repair_latex_json(raw))
|
|
self.assertEqual(parsed.solutions[0].solution_content, expected)
|
|
|
|
def test_mixed_correct_and_broken_escapes_in_all_extraction_fields(self):
|
|
cases = [
|
|
(ExamQuestions, 'questions', 'question_content', {'label': '1)'}),
|
|
(ExamSolutions, 'solutions', 'solution_content', {'label': '1)'}),
|
|
(ExamContext, 'contexts', 'context_content',
|
|
{'target_question_label': '1)', 'last_question_label': '2)'}),
|
|
(GroupRubrics, 'rubrics', 'rubric_content', {'label': '1)'})]
|
|
raw_content = r'$\circ \rightarrow \frac{1}{2} \not= \theta \begin{x} \unknown \underline{x}$\nSuite : $\\sqrt{x}$'
|
|
expected = r'$\circ \rightarrow \frac{1}{2} \not= \theta \begin{x} \unknown \underline{x}$' + '\n' + r'Suite : $\sqrt{x}$'
|
|
for model, collection, field, labels in cases:
|
|
with self.subTest(field=field):
|
|
raw = json.dumps({collection: [{**labels, field: 'PLACEHOLDER'}]}).replace('PLACEHOLDER', raw_content)
|
|
repaired = repair_latex_json(raw)
|
|
parsed = model.model_validate_json(repaired)
|
|
self.assertEqual(getattr(getattr(parsed, collection)[0], field), expected)
|
|
self.assertEqual(repair_latex_json(repaired), repaired)
|
|
|
|
def test_valid_json_is_unchanged(self):
|
|
content = 'Énoncé "cité"\nNouvelle ligne\ntexte\nnext\ni \ne \nu \tindent\r\n' + r'$\not= \frac{1}{2} \\ \begin{array}$'
|
|
raw = json.dumps({'question_content': content, 'label': r'\not'})
|
|
self.assertEqual(repair_latex_json(raw), raw)
|
|
self.assertEqual(repair_latex_json(r'{"rubric_content":"\u00e9 \/ \"ok\""}'),
|
|
r'{"rubric_content":"\u00e9 \/ \"ok\""}')
|
|
|
|
def test_only_content_values_are_repaired(self):
|
|
raw = r'{"label":"\not", "other":"\frac", "rubric_content":"\frac"}'
|
|
self.assertEqual(repair_latex_json(raw),
|
|
r'{"label":"\not", "other":"\frac", "rubric_content":"\\frac"}')
|
|
|
|
def test_does_not_repair_structural_errors(self):
|
|
with self.assertRaises(json.JSONDecodeError):
|
|
json.loads(repair_latex_json(r'{"question_content":"\frac", broken}'))
|