"""Unit tests for Document class.
Run from parent directory with command:
python3 -m unittest dumboclient filemodehelper documentmodel/test_document.py
"""
import random
import unittest
from documentmodel.document import Document
from documentmodel.documentparser import DocumentParser
from documentmodel.documentwriter import DocumentWriter
from documentmodel.exceptions import DocExistsError
from documentmodel.randutils import random_paragraph
from timdbtest import TimDbTest
[docs]class DocumentTest(TimDbTest):
[docs] def init_testdoc(self, doc_id=None):
d = Document(doc_id=doc_id)
self.assertFalse(d.exists())
db = self.get_db()
self.get_db().documents.create(str(d.doc_id), 0, d.doc_id)
db.close()
return d
[docs] def add_pars(self, d, num_docs):
pars = [d.add_paragraph(random_paragraph()).get_id() for _ in range(0, num_docs)]
self.assertEqual((num_docs, 0), d.get_version())
return pars
[docs] def test_document_create(self):
d = self.init_testdoc()
self.assertTrue(d.exists())
self.assertEqual(d.doc_id + 1, Document.get_next_free_id())
self.assertEqual((0, 0), d.get_version())
self.assertListEqual([], d.get_changelog())
d = self.init_testdoc()
self.assertTrue(d.exists())
self.assertEqual(d.doc_id + 1, Document.get_next_free_id())
self.assertEqual((0, 0), d.get_version())
self.assertListEqual([], d.get_changelog())
with self.assertRaises(DocExistsError):
d.create()
[docs] def test_addparagraph(self):
d = self.init_testdoc()
# Add first paragraph
par1 = d.add_paragraph('testing')
self.assertEqual('testing', par1.get_markdown())
self.assertTrue(d.has_paragraph(par1.get_id()))
self.assertFalse(d.has_paragraph(par1.get_id()[:-1]))
self.assertEqual((1, 0), d.get_version())
self.assertEqual(1, len(d.get_changelog()))
# Add different next paragraph
par2 = d.add_paragraph('different')
self.assertEqual('different', par2.get_markdown())
self.assertTrue(d.has_paragraph(par2.get_id()))
self.assertEqual((2, 0), d.get_version())
self.assertEqual(2, len(d.get_changelog()))
self.assertNotEqual(par1.get_id(), par2.get_id())
# Add next paragraph with same text as the first
par3 = d.add_paragraph('testing')
self.assertEqual('testing', par3.get_markdown())
self.assertTrue(d.has_paragraph(par3.get_id()))
self.assertEqual((3, 0), d.get_version())
self.assertEqual(3, len(d.get_changelog()))
self.assertNotEqual(par1.get_id(), par2.get_id())
# Add an empty paragraph
par3 = d.add_paragraph('')
self.assertEqual('', par3.get_markdown())
self.assertTrue(d.has_paragraph(par3.get_id()))
self.assertEqual((4, 0), d.get_version())
self.assertEqual(4, len(d.get_changelog()))
self.assertNotEqual(par2.get_id(), par3.get_id())
self.assertNotEqual(par1.get_id(), par3.get_id())
[docs] def test_iterator(self):
d = self.init_testdoc()
pars = [d.add_paragraph(random_paragraph()) for _ in range(0, 10)]
self.assertEqual((10, 0), d.get_version())
self.assertEqual(10, len(d.get_changelog()))
self.assertListEqual([p.get_id() for p in pars], [par.get_id() for par in d])
self.assertListEqual([p.get_hash() for p in pars], [par.get_hash() for par in d])
[docs] def test_delparagraph(self):
d = self.init_testdoc()
pars = self.add_pars(d, 10)
# Delete first paragraph
d.delete_paragraph(pars[0])
self.assertFalse(d.has_paragraph(pars[0]))
pars.remove(pars[0])
self.assertListEqual(pars, [par.get_id() for par in d])
self.assertEqual((11, 0), d.get_version())
self.assertEqual(11, len(d.get_changelog()))
# Delete from the middle
d.delete_paragraph(pars[2])
self.assertFalse(d.has_paragraph(pars[2]))
pars.remove(pars[2])
self.assertListEqual(pars, [par.get_id() for par in d])
self.assertEqual((12, 0), d.get_version())
self.assertEqual(12, len(d.get_changelog()))
# Delete last paragraph
n = len(pars)
d.delete_paragraph(pars[n - 1])
self.assertFalse(d.has_paragraph(pars[n - 1]))
pars.remove(pars[n - 1])
self.assertListEqual(pars, [par.get_id() for par in d])
self.assertEqual((13, 0), d.get_version())
self.assertEqual(13, len(d.get_changelog()))
[docs] def test_insertparagraph(self):
d = self.init_testdoc()
pars = self.add_pars(d, 10)
# Insert as first
par = d.insert_paragraph('new first', pars[0])
pars = [par.get_id()] + pars
self.assertListEqual(pars, [par.get_id() for par in d])
self.assertEqual((11, 0), d.get_version())
self.assertEqual(11, len(d.get_changelog()))
# Insert in the middle
par = d.insert_paragraph('middle', pars[4])
pars = pars[0:4] + [par.get_id()] + pars[4:]
self.assertListEqual(pars, [par.get_id() for par in d])
self.assertEqual((12, 0), d.get_version())
self.assertEqual(12, len(d.get_changelog()))
# Insert as last
par = d.insert_paragraph('last', None)
pars.append(par.get_id())
self.assertListEqual(pars, [par.get_id() for par in d])
self.assertEqual((13, 0), d.get_version())
self.assertEqual(13, len(d.get_changelog()))
[docs] def test_get_html(self):
d = self.init_testdoc()
par1 = d.add_paragraph('just text')
self.assertEqual('<p>just text</p>', par1.get_html())
par1 = d.add_paragraph('# Heading')
self.assertEqual('<h1 id="heading">Heading</h1>', par1.get_html())
[docs] def test_modify(self):
d = self.init_testdoc()
pars = [d.add_paragraph(random_paragraph()) for _ in range(0, 10)]
self.assertEqual((10, 0), d.get_version())
par2_id = pars[2].get_id()
par2_hash = pars[2].get_hash()
old_md = pars[2].get_markdown()
new_text = 'new_text'
par2_mod = d.modify_paragraph(par2_id, new_text)
self.assertEqual(par2_id, par2_mod.get_id())
self.assertEqual(new_text, d.get_paragraph(par2_id).get_markdown())
self.assertEqual(new_text, par2_mod.get_markdown())
self.assertNotEqual(par2_hash, par2_mod.get_hash())
self.assertEqual((10, 1), d.get_version())
self.assertEqual(11, len(d.get_changelog()))
par2_mod = d.modify_paragraph(par2_id, old_md)
self.assertEqual(old_md, par2_mod.get_markdown())
self.assertEqual(old_md, d.get_paragraph(par2_id).get_markdown())
for i in range(0, 10):
par2_id = pars[i].get_id()
par2_hash = pars[i].get_hash()
new_text = random_paragraph()
par2_mod = d.modify_paragraph(par2_id, new_text)
self.assertEqual(par2_id, par2_mod.get_id())
self.assertEqual(new_text, par2_mod.get_markdown())
self.assertNotEqual(par2_hash, par2_mod.get_hash())
self.assertEqual((10, i + 3), d.get_version())
self.assertEqual(13 + i, len(d.get_changelog()))
[docs] def test_document_remove(self):
free = Document.get_next_free_id()
db = self.get_db()
for i in range(free, free + 5):
if i != free + 2:
self.init_testdoc(i)
self.assertEqual(free + 5, Document.get_next_free_id())
with self.assertRaises(DocExistsError):
Document.remove(doc_id=free + 2)
db.documents.delete(free + 1)
self.assertFalse(Document.doc_exists(doc_id=free + 1))
self.assertEqual(free + 5, Document.get_next_free_id())
db.documents.delete(free + 4)
self.assertFalse(Document.doc_exists(doc_id=free + 4))
self.assertEqual(free + 4, Document.get_next_free_id())
db.documents.delete(free)
self.assertFalse(Document.doc_exists(doc_id=free))
self.assertEqual(free + 4, Document.get_next_free_id())
db.documents.delete(free + 3)
self.assertFalse(Document.doc_exists(doc_id=free + 3))
self.assertEqual(free, Document.get_next_free_id())
db.close()
[docs] def test_update(self):
self.maxDiff = None
random.seed(0)
for i in range(1, 5):
d = self.init_testdoc()
for _ in range(0, i):
d.add_paragraph(random_paragraph())
fulltext = d.export_markdown()
d.update(fulltext, fulltext)
self.assertEqual(fulltext, d.export_markdown())
dp = DocumentParser(fulltext)
blocks = dp.get_blocks()
random.shuffle(blocks)
blocks[0]['md'] = 'modified'
new_text = DocumentWriter(blocks).get_text()
d.update(new_text, fulltext)
blocks = DocumentParser(new_text).add_missing_attributes().get_blocks()
self.assertListEqual(blocks, DocumentParser(d.export_markdown(export_hashes=True)).get_blocks())
[docs] def test_update_section(self):
self.maxDiff = None
random.seed(0)
for i in range(6, 10):
d = self.init_testdoc()
for _ in range(0, i):
d.add_paragraph(random_paragraph())
ids = [par.get_id() for par in d]
new_pars = DocumentParser('#-\none\n\n#-\ntwo\n\n#-\nthree').add_missing_attributes().get_blocks()
start_repl_index = 1
end_repl_index = 4
repl_length = len(new_pars)
length_diff = repl_length - (end_repl_index - start_repl_index + 1)
section_text = DocumentWriter(new_pars).get_text()
d.update_section(section_text, ids[start_repl_index], ids[end_repl_index])
new_ids = [par.get_id() for par in d]
self.assertListEqual([par['id'] for par in new_pars],
new_ids[start_repl_index:start_repl_index + repl_length])
self.assertEqual(length_diff, len(new_ids) - len(ids))
[docs] def test_macros(self):
d = self.init_testdoc()
settings_par = d.add_paragraph('```\n'
'macro_delimiter: "%%"\n'
'macros:\n'
' testmacro: testvalue\n'
' year: "2015"\n'
'```', attrs={'settings': ''})
macro_par = d.add_paragraph('this is %%testmacro%% and year is %%year%%')
macro_par = d.get_paragraph(macro_par.get_id()) # Put the paragraph in cache
self.assertDictEqual({'macros': {'testmacro': 'testvalue', 'year': '2015'},
'macro_delimiter': '%%'}, d.get_settings().get_dict())
self.assertEqual('<p>this is testvalue and year is 2015</p>', macro_par.get_html())
d = Document(d.doc_id) # Make a new instance of the document to test cache invalidation
d.modify_paragraph(settings_par.get_id(),
'```\n'
'macro_delimiter: "%%"\n'
'macros:\n'
' testmacro: anothervalue\n'
' year: "2016"\n'
'```',
new_attrs={'settings': ''})
macro_par = d.get_paragraph(macro_par.get_id())
self.assertEqual('<p>this is anothervalue and year is 2016</p>', macro_par.get_html())
[docs] def test_import(self):
timdb = self.get_db()
timdb.documents.import_document_from_file('example_docs/mmcq_example.md',
'Multiple choice plugin example',
timdb.users.get_anon_group_id())
timdb.close()
if __name__ == '__main__':
unittest.main()