Source code for timApp.tests.db.test_references

"""Unit tests for testing paragraph referencing."""

import unittest
from typing import Optional

from timApp.document.docparagraph import DocParagraph
from timApp.document.document import Document
from timApp.document.documentparser import DocumentParser
from timApp.document.viewcontext import default_view_ctx
from timApp.tests.db.timdbtest import TimDbTest
from timApp.timdb.exceptions import TimDbException


[docs]def add_ref_paragraph( doc: Document, src_par: DocParagraph, text: str | None = None, attrs: dict | None = None, ) -> DocParagraph: ref_attrs = {} if attrs is None else attrs.copy() ref_attrs["rp"] = src_par.get_id() ref_attrs["rt"] = src_par.get_hash() rd = src_par.get_doc_id() if doc.get_settings().get_source_document() != rd: ref_attrs["rd"] = str(rd) if text is not None: ref_attrs["r"] = "tr" else: text = "" return doc.add_paragraph(text, attrs=ref_attrs)
[docs]def add_area_ref_paragraph( doc: Document, src_doc: "Document", src_area_name: str, text: str | None = None, attrs: dict | None = None, ) -> DocParagraph: ref_attrs = {} if attrs is None else attrs.copy() ref_attrs["ra"] = src_area_name ref_attrs.pop("rt", None) if doc.get_settings().get_source_document() != src_doc.doc_id: ref_attrs["rd"] = str(src_doc.doc_id) if text is not None: ref_attrs["r"] = "tr" else: text = "" return doc.add_paragraph(text, attrs=ref_attrs)
[docs]class RefTest(TimDbTest):
[docs] def dict_merge(self, a, b): c = a.copy() c.update(b) return c
[docs] def dict_issubset(self, a, b): return set(a.items()).issubset(set(b.items()))
[docs] def assert_dict_issubset(self, a, b): self.assertTrue(self.dict_issubset(a, b), f"{a} is not a subset of {b}")
[docs] def setUp(self): super().setUp() self.init_testdb()
[docs] def init_testdb(self): db = self.get_db() self.src_doc = self.create_doc().document self.ref_doc = self.create_doc().document self.src_par = self.src_doc.add_paragraph("testpar", attrs={"a": "1", "b": "2"}) self.assertEqual( self.src_par.get_id(), self.src_doc.get_paragraphs()[0].get_id() ) return db
[docs] def test_simpleref(self): ref_par = add_ref_paragraph(self.ref_doc, self.src_par) self.assertEqual(1, len(self.ref_doc.get_paragraphs())) self.assertEqual(ref_par.get_id(), self.ref_doc.get_paragraphs()[0].get_id()) self.assertEqual("", ref_par.get_markdown()) rendered_pars = ref_par.get_referenced_pars() self.assertEqual(1, len(rendered_pars)) self.assertEqual(self.src_par.get_id(), rendered_pars[0].get_id()) self.assertEqual(self.src_par.get_markdown(), rendered_pars[0].get_markdown()) self.assertEqual( self.src_par.get_html(default_view_ctx), rendered_pars[0].get_html(default_view_ctx), ) self.assertEqual(self.src_par.get_attrs(), rendered_pars[0].get_attrs())
[docs] def test_translation(self): ref_attrs = {"foo": "fffoooo", "bar": "baaaa"} ref_par = add_ref_paragraph( self.ref_doc, self.src_par, "translation", attrs=ref_attrs ) self.assertEqual(1, len(self.ref_doc.get_paragraphs())) self.assertEqual(ref_par.get_id(), self.ref_doc.get_paragraphs()[0].get_id()) self.assertEqual("translation", ref_par.get_markdown()) rendered_pars = ref_par.get_referenced_pars() self.assertEqual(1, len(rendered_pars)) self.assertEqual(self.src_par.get_id(), rendered_pars[0].get_id()) self.assertEqual(ref_par.get_markdown(), rendered_pars[0].get_markdown()) self.assertEqual( ref_par.get_html(default_view_ctx), rendered_pars[0].get_html(default_view_ctx), ) self.assertEqual( self.dict_merge(self.src_par.get_attrs(), ref_attrs), rendered_pars[0].get_attrs(), )
[docs] def test_circular(self): ref_par = add_ref_paragraph(self.ref_doc, self.src_par) self.assertEqual(1, len(self.ref_doc.get_paragraphs())) self.assertEqual(ref_par.get_id(), self.ref_doc.get_paragraphs()[0].get_id()) self.assertEqual("", ref_par.get_markdown()) self.src_par.set_attr("rd", str(self.ref_doc.doc_id)) self.src_par.set_attr("rp", ref_par.get_id()) self.src_doc.modify_paragraph_obj(self.src_par.get_id(), self.src_par) self.ref_doc.clear_mem_cache() ref_par.ref_pars = {} self.assertRaises(TimDbException, ref_par.get_referenced_pars) self.assertRaises(TimDbException, self.src_par.get_referenced_pars)
[docs] def test_transitive(self): # Reference to the original paragraph ref_par1 = add_ref_paragraph(self.ref_doc, self.src_par) self.assertEqual(1, len(self.ref_doc.get_paragraphs())) self.assertEqual(ref_par1.get_id(), self.ref_doc.get_paragraphs()[0].get_id()) self.assertEqual("", ref_par1.get_markdown()) # Reference to the reference above ref_doc2 = self.create_doc().document ref_par2 = add_ref_paragraph(ref_doc2, ref_par1) self.assertEqual(1, len(ref_doc2.get_paragraphs())) self.assertEqual(ref_par2.get_id(), ref_doc2.get_paragraphs()[0].get_id()) self.assertEqual("", ref_par2.get_markdown()) # Render the reference to the reference rendered_pars = ref_par2.get_referenced_pars() self.assertEqual(1, len(rendered_pars)) self.assertEqual(self.src_par.get_id(), rendered_pars[0].get_id()) self.assertEqual(self.src_par.get_markdown(), rendered_pars[0].get_markdown()) self.assertEqual( self.src_par.get_html(default_view_ctx), rendered_pars[0].get_html(default_view_ctx), ) self.assertEqual(self.src_par.get_attrs(), rendered_pars[0].get_attrs()) # Declare some new attributes ref_par1.set_attr("foo", "fffooo") ref_par2.set_attr("bar", "baaaa") self.ref_doc.modify_paragraph_obj(ref_par1.get_id(), ref_par1) ref_doc2.modify_paragraph_obj(ref_par2.get_id(), ref_par2) expected_attrs = self.src_par.get_attrs() expected_attrs["foo"] = "fffooo" expected_attrs["bar"] = "baaaa" rendered_pars = ref_par2.get_referenced_pars() self.assert_dict_issubset(expected_attrs, rendered_pars[0].get_attrs())
[docs] def test_editparagraph_cite(self): src_md = self.src_par.get_exported_markdown() self.assertRegex(src_md, '^#- *\\{([ab]="[21]" ?){2}\\}\ntestpar\n$') ref_par = add_ref_paragraph(self.ref_doc, self.src_par) self.assertEqual(1, len(self.ref_doc.get_paragraphs())) self.assertEqual(ref_par.get_id(), self.ref_doc.get_paragraphs()[0].get_id()) self.assertEqual("", ref_par.get_markdown()) ref_md = ref_par.get_exported_markdown() dp = DocumentParser(ref_md) dp.validate_structure().raise_if_has_any_issues() ref_blocks = [ DocParagraph.create(doc=ref_par.doc, md=par["md"], attrs=par.get("attrs")) for par in dp.get_blocks() ] self.assertEqual(1, len(ref_blocks)) self.assertEqual("", ref_blocks[0].get_markdown()) self.assertEqual(str(self.src_doc.doc_id), str(ref_blocks[0].get_attr("rd"))) self.assertEqual(self.src_par.get_id(), ref_blocks[0].get_attr("rp")) self.assertEqual(self.src_par.get_hash(), ref_blocks[0].get_attr("rt"))
[docs] def test_editparagraph_citearea(self): areastart_par = self.src_doc.add_paragraph("", attrs={"area": "testarea"}) area_par1 = self.src_doc.add_paragraph("Testarea par 1", attrs={"x": 1, "y": 2}) area_par2 = self.src_doc.add_paragraph("Testarea par 2", attrs={"a": 3, "b": 4}) areaend_par = self.src_doc.add_paragraph("", attrs={"area_end": "testarea"}) areastart_md = areastart_par.get_exported_markdown() areapar1_md = area_par1.get_exported_markdown() areapar2_md = area_par2.get_exported_markdown() areaend_md = areaend_par.get_exported_markdown() self.assertRegex(areastart_md, '^#- *\\{area="testarea" ?\\}\n+$') self.assertRegex( areapar1_md, '^#- *\\{([xy]="[12]" ?){2}\\}\nTestarea par 1\n$' ) self.assertRegex( areapar2_md, '^#- *\\{([ab]="[34]" ?){2}\\}\nTestarea par 2\n$' ) self.assertRegex(areaend_md, '^#- *\\{area_end="testarea" ?\\}\n+$') ref_par = add_area_ref_paragraph(self.ref_doc, self.src_doc, "testarea") ref_md = ref_par.get_exported_markdown() src_docid = str(self.src_doc.doc_id) self.assertRegex( ref_md, '^#- *\\{(((ra="testarea")|(rd="' + src_docid + '")) ?){2}\\}\n+$' )
# todo: test the contents of the rendered area
[docs] def test_editparagraph_translate(self): src_md = self.src_par.get_exported_markdown() self.assertRegex(src_md, '^#- *\\{([ab]="[21]" ?){2}\\}\ntestpar\n$') empty_refpar = add_ref_paragraph(self.ref_doc, self.src_par, "") self.assertEqual(1, len(self.ref_doc.get_paragraphs())) self.assertEqual( empty_refpar.get_id(), self.ref_doc.get_paragraphs()[0].get_id() ) self.assertEqual("", empty_refpar.get_markdown()) ref_md = empty_refpar.get_exported_markdown() dp = DocumentParser(ref_md) dp.validate_structure().raise_if_has_any_issues() ref_blocks = [ DocParagraph.create( doc=empty_refpar.doc, md=par["md"], attrs=par.get("attrs") ) for par in dp.get_blocks() ] self.assertEqual(1, len(ref_blocks)) self.assertEqual(self.src_par.get_markdown(), ref_blocks[0].get_markdown()) self.assertEqual(str(self.src_doc.doc_id), str(ref_blocks[0].get_attr("rd"))) self.assertEqual(self.src_par.get_id(), ref_blocks[0].get_attr("rp")) self.assertEqual(self.src_par.get_hash(), ref_blocks[0].get_attr("rt")) self.assertEqual("tr", ref_blocks[0].get_attr("r")) ref_attrs = {"foo": "fffoooo", "bar": "baaaa"} ref_par = add_ref_paragraph( self.ref_doc, self.src_par, "translation", attrs=ref_attrs ) self.assertEqual(2, len(self.ref_doc.get_paragraphs())) self.assertEqual(ref_par.get_id(), self.ref_doc.get_paragraphs()[1].get_id()) self.assertEqual("translation", ref_par.get_markdown()) ref_md = ref_par.get_exported_markdown() dp = DocumentParser(ref_md) dp.validate_structure().raise_if_has_any_issues() ref_blocks = [ DocParagraph.create(doc=ref_par.doc, md=par["md"], attrs=par.get("attrs")) for par in dp.get_blocks() ] self.assertEqual(1, len(ref_blocks)) self.assertEqual(ref_par.get_markdown(), ref_blocks[0].get_markdown()) self.assertEqual(str(self.src_doc.doc_id), str(ref_blocks[0].get_attr("rd"))) self.assertEqual(self.src_par.get_id(), ref_blocks[0].get_attr("rp")) self.assertEqual(self.src_par.get_hash(), ref_blocks[0].get_attr("rt")) self.assertEqual("tr", ref_blocks[0].get_attr("r"))
[docs] def test_editparagraph_translatearea(self): areastart_par = self.src_doc.add_paragraph("", attrs={"area": "testarea"}) area_par1 = self.src_doc.add_paragraph("Testarea par 1", attrs={"x": 1, "y": 2}) area_par2 = self.src_doc.add_paragraph("Testarea par 2", attrs={"a": 3, "b": 4}) areaend_par = self.src_doc.add_paragraph("", attrs={"area_end": "testarea"}) areastart_md = areastart_par.get_exported_markdown() areapar1_md = area_par1.get_exported_markdown() areapar2_md = area_par2.get_exported_markdown() areaend_md = areaend_par.get_exported_markdown() self.assertRegex(areastart_md, '^#- *\\{area="testarea" ?\\}\n+$') self.assertRegex( areapar1_md, '^#- *\\{([xy]="[12]" ?){2}\\}\nTestarea par 1\n$' ) self.assertRegex( areapar2_md, '^#- *\\{([ab]="[34]" ?){2}\\}\nTestarea par 2\n$' ) self.assertRegex(areaend_md, '^#- *\\{area_end="testarea" ?\\}\n+$') ref_par = add_area_ref_paragraph( self.ref_doc, self.src_doc, "testarea", "translation" ) ref_md = ref_par.get_exported_markdown() src_docid = str(self.src_doc.doc_id) self.assertRegex( ref_md, '^#- *\\{(((ra="testarea")|(rd="' + src_docid + '")|(r="tr")) ?){3}\\}\ntranslation\n+$', ) ref_par = self.ref_doc.modify_paragraph(ref_par.get_id(), "") ref_md = ref_par.get_exported_markdown() self.assertRegex( ref_md, '^#- *\\{(((ra="testarea")|(rd="' + src_docid + '")|(r="tr")) ?){3}\\}\n+$', )
# todo: test the contents of the rendered area
[docs] def test_settings_not_inherited(self): """Settings attribute is not inherited from a referring paragraph.""" ref = self.src_par.create_reference(self.ref_doc) ref.set_attr("settings", "") self.ref_doc.add_paragraph_obj(ref) deref = ref.get_referenced_pars()[0] self.assertNotIn("settings", deref.get_attrs()) self.src_par.set_attr("settings", "") self.src_par.set_markdown("") self.src_par.save() ref.ref_pars = {} ref.doc.clear_mem_cache() deref = ref.get_referenced_pars()[0] self.assertIn("settings", deref.get_attrs())
[docs] def test_reference_classes(self): """Classes of reference and source paragraphs are merged.""" ref = self.src_par.create_reference(self.ref_doc) ref.add_class("red", "green") self.src_par.add_class("blue", "white", "orange") self.src_par.save() deref = ref.get_referenced_pars()[0] ref.ref_pars = {} self.assertEqual( {"blue", "white", "orange", "red", "green"}, set(deref.classes) ) self.assertEqual(5, len(deref.classes)) self.src_par.classes = None self.src_par.save() ref.doc.clear_mem_cache() deref = ref.get_referenced_pars()[0] self.assertEqual({"red", "green"}, set(deref.classes)) self.assertEqual(2, len(deref.classes)) ref.ref_pars = {} self.src_par.add_class("blue", "white", "orange") ref.classes = None self.src_par.save() ref.doc.clear_mem_cache() deref = ref.get_referenced_pars()[0] self.assertEqual({"blue", "white", "orange"}, set(deref.classes)) self.assertEqual(3, len(deref.classes))