import unittest import docx from docx import Document from md2gost.renderable.paragraph_sizer import Font, ParagraphSizer from md2gost.renderable.listing import LISTING_OFFSET from docx.shared import Pt, Mm, Cm from . import _create_test_document, _EMUS_PER_PX delta = 10/29 class TestFont(unittest.case.TestCase): def test_get_text_width(self): font = Font("Times New Roman", False, False, 14) self.assertAlmostEqual(37.5, font.get_text_width("hello") / _EMUS_PER_PX, delta=delta) def test_get_text_width_short(self): font = Font("Times New Roman", False, False, 14) self.assertAlmostEqual(15, font.get_text_width("in") / _EMUS_PER_PX, delta=delta) def test_get_text_width_long(self): font = Font("Times New Roman", False, False, 14) self.assertAlmostEqual(245, font.get_text_width("Электроэнцефалографический") / _EMUS_PER_PX, delta=delta) def test_get_text_width_bold(self): font = Font("Times New Roman", True, False, 14) self.assertAlmostEqual(39, font.get_text_width("hello") / _EMUS_PER_PX, delta=delta) def test_get_text_width_italic(self): font = Font("Times New Roman", False, True, 14) self.assertAlmostEqual(37.5, font.get_text_width("hello") / _EMUS_PER_PX, delta=delta) def test_get_text_width_bold_italic(self): font = Font("Times New Roman", True, True, 14) self.assertAlmostEqual(38.5, font.get_text_width("hello") / _EMUS_PER_PX, delta=delta) def test_get_line_height_times(self): font = Font("Times New Roman", False, False, 14) self.assertAlmostEqual(21.4, font.get_line_height() / _EMUS_PER_PX, delta=delta) def test_get_line_height_times_large(self): font = Font("Times New Roman", False, False, 50) self.assertAlmostEqual(77, font.get_line_height() / _EMUS_PER_PX, delta=delta) def test_get_line_height_calibri(self): font = Font("Calibri", False, False, 14) self.assertAlmostEqual(23, font.get_line_height() / _EMUS_PER_PX, delta=delta) def test_get_line_height_consolas(self): font = Font("Consolas", False, False, 20) self.assertAlmostEqual(31, font.get_line_height() / _EMUS_PER_PX, delta=delta) def test_get_line_height_courier(self): font = Font("Courier New", False, False, 12) self.assertAlmostEqual(18.3, font.get_line_height() / _EMUS_PER_PX, delta=delta) def test_is_mono_courier(self): font = Font("Courier New", False, False, 12) self.assertTrue(font.is_mono) def test_is_mono_times(self): font = Font("Times New Roman", False, False, 12) self.assertFalse(font.is_mono) class TestParagraphSizer(unittest.TestCase): def setUp(self): self._document, self._max_height, self._max_width = _create_test_document() def test_count_lines(self): paragraph = self._document.add_paragraph() paragraph.add_run("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam lacinia fringilla lectus, " "nec euismod odio convallis sed. Nunc ac libero ultricies, condimentum neque et, " "fermentum urna. Donec feugiat diam sed nulla rutrum, sit amet accumsan odio tempor. Sed " "bibendum ante at orci faucibus, sed dignissim nisi finibus. Vestibulum luctus eget enim et " "mattis. In porta convallis ipsum eget dignissim. Ut orci ante, bibendum ut lorem quis, " "gravida molestie neque. Nulla vitae sapien sed risus gravida elementum non eu lorem. " "Quisque ac turpis nisl.") ps = ParagraphSizer(paragraph, None, self._max_width) self.assertEqual(7, ps.count_lines(paragraph.runs, self._max_width, paragraph.style.font, Cm(1.25))) def test_count_lines2(self): paragraph = self._document.add_paragraph() paragraph.add_run("Ordered lists are useful when you want to present items in a specific order. This is additional text for illustration. Ordered lists are useful when you want to present items in a specific order. This is additional text for illustration. Ordered lists are useful when you want to present items in a specific order. This is additional text for illustration.") ps = ParagraphSizer(paragraph, None, self._max_width) self.assertEqual(4, ps.count_lines(paragraph.runs, self._max_width, paragraph.style.font, Cm(1.25))) def test_count_lines_short_last_line(self): paragraph = self._document.add_paragraph() paragraph.add_run("Nam porta urna vel turpis lobortis, nec congue sem suscipit. Mauris ac facilisis metus, " "non fermentum turpis. Nunc erat ipsum, interdum sit amet odio ut, vulputate feugiat arcu. " "Donec nec rhoncus metus, nec pharetra mauris. Proin magna arcu, porta vitae eleifend et, " "scelerisque vel nunc. Ut ut neque sed libero mattis finibus quis eu tortor. Quisque " "molestie tempus neque rutrum vestibulum. Proin dui odio, tincidunt nec lectus at, " "mollis tristique diam. Nulla arcu ante, fringilla sit amet pretium venenatis, ultricies a " "elit. Sed ac velit a dolor interdum sollicitudin. Donec tortor leo, finibus eu nisi id, " "cursus luctus diam. Vestibulum ex nulla, fringilla pellentesque diam eu, rhoncus suscipit " "ligula. Mauris vestibulum libero erat, vitae mollis orci ultricies at. Nulla maximus " "elementum nulla at ultrices. Vestibulum pellentesque vulputate orci, quis finibus") ps = ParagraphSizer(paragraph, None, self._max_width) self.assertEqual(11, ps.count_lines(paragraph.runs, self._max_width, paragraph.style.font, Cm(1.25))) def test_count_lines_short_last_line2(self): paragraph = self._document.add_paragraph() paragraph.add_run("OpenAI is a leading artificial intelligence research organization, known for advancements in language models like GPT. Click the link to learn more. Hello world —") ps = ParagraphSizer(paragraph, None, self._max_width) self.assertEqual(3, ps.count_lines(paragraph.runs, self._max_width, paragraph.style.font, Cm(1.25))) def test_count_lines_long_last_line(self): paragraph = self._document.add_paragraph() paragraph.add_run("Donec finibus elementum lectus non ultricies. Pellentesque dictum tellus a neque rutrum " "euismod. Fusce lobortis id est ut bibendum. Integer quis nunc convallis, maximus justo " "fermentum, vestibulum metus. Nulla fringilla quam in purus laoreet, eu rhoncus risus " "condimentum. Sed eget odio urna. Integer mi diam, aliquam id rhoncus vitae, lacinia quis " "augue. Nulla ultrices velit vel urna accumsan, et feugiat nunc fringilla. Praesent feugiat " "neque ac tellus rutrum congue. Sed congue libero congue, blandit felis ac, " "lobortis libero. Phasellus eleifend ex vulputate odio mollis dictum.") ps = ParagraphSizer(paragraph, None, self._max_width) self.assertEqual(7, ps.count_lines(paragraph.runs, self._max_width, paragraph.style.font, Cm(1.25))) def test_count_lines_long_last_line2(self): paragraph = self._document.add_paragraph() paragraph.add_run('Markdown supports rendering mathematical formulas using LaTeX syntax. This allows you to include complex equations and mathematical notation in your documents.') ps = ParagraphSizer(paragraph, None, self._max_width) self.assertEqual(2, ps.count_lines(paragraph.runs, self._max_width, paragraph.style.font, Cm(1.25))) def test_count_lines_long_last_line3(self): paragraph = self._document.add_paragraph() paragraph.add_run("Markdown's LaTeX syntax allows you to easily write fractions and exponents. For instance, you can represent the derivative of a function InlineFormula is not supported with respect to InlineFormula is not supported using the following notation:") ps = ParagraphSizer(paragraph, None, self._max_width) self.assertEqual(3, ps.count_lines(paragraph.runs, self._max_width, paragraph.style.font, Cm(1.25))) def test_count_lines_long_word(self): paragraph = self._document.add_paragraph() paragraph.add_run("verylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongword") ps = ParagraphSizer(paragraph, None, self._max_width) self.assertEqual(3, ps.count_lines(paragraph.runs, self._max_width, paragraph.style.font, Cm(1.25))) def test_count_lines_long_word_2(self): paragraph = self._document.add_paragraph() paragraph.add_run("someword verylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongwordverylongword") ps = ParagraphSizer(paragraph, None, self._max_width) self.assertEqual(4, ps.count_lines(paragraph.runs, self._max_width, paragraph.style.font, Cm(1.25))) def test_count_lines_courier(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run(""" table._cells[0]._element.append(paragraph_rendered_info.docx_element._element)""") ps = ParagraphSizer(paragraph, None, self._max_width-LISTING_OFFSET) self.assertEqual(3, ps.count_lines(paragraph.runs, self._max_width-LISTING_OFFSET, paragraph.style.font, 0)) def test_count_lines_courier2(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ continuation_paragraph = Paragraph(self.parent)""") ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(1, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0)) def test_count_lines_courier3(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo""") ps = ParagraphSizer(paragraph, None, self._max_width - Pt(14)) self.assertEqual(2, ps.count_lines(paragraph.runs, self._max_width - Pt(14), paragraph.style.font, 0)) def test_count_lines_courier4(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ def add_link(self, text: str, url: str, is_bold: bool = None, is_italic: bool = None):""") ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(2, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0)) def test_count_lines_courier5(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ self._docx_paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.EXACTLY""") ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(2, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0)) def test_count_lines_courier6(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ # and "Heading" in previous_rendered.docx_element.style.name\\""") ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(2, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0)) def test_count_lines_courier7(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ run = DocxRun(create_element("w:r"), self._docx_paragraph)""") ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(1, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0, True)) def test_count_lines_courier7(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ # and ((min(2, height_data.lines) - 1) * height_data.line_spacing + 1) * height_data.line_height\\""") ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(2, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0, True)) def test_count_lines_courier8(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ return self._docx_paragraph.paragraph_format.first_line_indent""") ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(2, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0, True)) def test_count_lines_courier9(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ self._docx_paragraph.paragraph_format.first_line_indent = value""") ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(2, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0, True)) def test_count_lines_courier10(self): paragraph = self._document.add_paragraph(style="Code") paragraph.add_run( """ if previous_rendered and isinstance(previous_rendered.docx_element, DocxParagraph) else None,""") ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(3, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0, True)) def test_count_lines_courier_multiple_runs(self): paragraph = self._document.add_paragraph(style="Code") for run_text in ['', ' ', 'run', ' ', '=', ' ', 'DocxRun', '(', 'create_element', '(', '"', 'w:r', '"', ')', ',', ' ', 'self', '.', '_docx_paragraph', ')']: paragraph.add_run(run_text) ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(1, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0, True)) def test_count_lines_courier_multiple_runs2(self): paragraph = self._document.add_paragraph(style="Code") for run_text in ['', ' ', '-', '>', ' ', 'Generator', '[', 'RenderedInfo', ' ', '|', ' ', 'Renderable', ',', ' ', 'None', ',', ' ', 'None', ']', ':']: paragraph.add_run(run_text) ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) self.assertEqual(1, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0, True)) # def test_count_lines_courier_multiple_runs3(self): # paragraph = self._document.add_paragraph(style="Code") # for run_text in ['', ' ', '-', '>', ' ', 'Generator', '[', 'RenderedInfo', ' ', '|', ' ', 'Renderable', ',', ' ', 'None', ',', ' ', 'None', ']', ':']: # paragraph.add_run(run_text) # # ps = ParagraphSizer(paragraph, None, self._max_width - LISTING_OFFSET) # # self.assertEqual(3, ps.count_lines(paragraph.runs, self._max_width - LISTING_OFFSET, paragraph.style.font, 0, True))