| 1 | import unittest |
| 2 | import xml.etree.ElementTree as ET |
| 3 | from native_format import compare_formats, native_characters, Runs |
| 4 | from native_xml import ns, Text, project_text |
| 5 | |
| 6 | |
| 7 | class FormatOracleTest(unittest.TestCase): |
| 8 | def test_native_omits_exactly_one_final_paragraph_break(self): |
| 9 | for stored, exported in [('A\r\r', 'A\n'), ('\rA\r', '\nA'), ('\r', ''), ('\r\r', '\n'), ('A\n', 'A\n')]: |
| 10 | with self.subTest(stored=stored): |
| 11 | node = {'format': {'bold': True}, 'kind': {'text': stored, 'paragraph_style': None, |
| 12 | 'runs': [{'start': 0, 'end': len(stored), 'format': None}]}} |
| 13 | native = [[(c, {'bold': True}) for c in exported]] |
| 14 | self.assertEqual(compare_formats({'nodes': {}}, [node], native), (len(exported), [])) |
| 15 | with self.assertRaisesRegex(AssertionError, 'Visible text runs differ'): |
| 16 | compare_formats({'nodes': {}}, [node], [[(c, {'bold': True}) for c in exported + '\n']]) |
| 17 | |
| 18 | def test_native_break_formatting_and_tabs_preserve_distinct_source_text(self): |
| 19 | html = '<b>A<br><br>\nB</b><br>\nC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;D' |
| 20 | expected = 'A\n\nB\nC' + '\u00a0' * 8 + 'D' |
| 21 | self.assertEqual(''.join(Text(html).parts), expected) |
| 22 | runs = Runs(html, {}) |
| 23 | self.assertEqual(''.join(c for c, _ in runs.characters), expected) |
| 24 | self.assertTrue(runs.characters[2][1]['bold']) |
| 25 | self.assertNotIn('bold', runs.characters[4][1]) |
| 26 | self.assertEqual(project_text('A\r\rB\rC\tD'), expected) |
| 27 | self.assertEqual(project_text('\u00a0' * 8), '\u00a0' * 8) |
| 28 | |
| 29 | def test_utf16_run_boundaries_and_inherited_native_style(self): |
| 30 | page = ET.fromstring('''<one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote"> |
| 31 | <one:QuickStyleDef index="0" font="Calibri" fontSize="14" bold="true" strikethrough="true"/> |
| 32 | <one:Outline><one:OE quickStyleIndex="0"><one:T>A&lt;span style="font-style:italic"&gt;😀&lt;/span&gt;B</one:T></one:OE></one:Outline> |
| 33 | </one:Page>''') |
| 34 | node = {'format': {}, 'kind': {'text': 'A😀B', 'paragraph_style': 'base', 'runs': [ |
| 35 | {'start': 0, 'end': 1, 'format': None}, {'start': 1, 'end': 3, 'format': 'italic'}, |
| 36 | {'start': 3, 'end': 4, 'format': None}, |
| 37 | ]}} |
| 38 | space = {'nodes': {'base': {'format': {'bold': True, 'font': 'Calibri', 'font_size': 14.0}}, |
| 39 | 'italic': {'format': {'italic': True}}}} |
| 40 | expected = native_characters(page, page.findall('one:Outline', ns)) |
| 41 | self.assertTrue(expected[0][0][1]['strike']) |
| 42 | count, differences = compare_formats(space, [node], expected) |
| 43 | self.assertEqual((count, differences), (10, [])) |
| 44 | space['nodes']['italic']['format']['italic'] = False |
| 45 | _, differences = compare_formats(space, [node], expected) |
| 46 | self.assertEqual(differences, [{'paragraph': 0, 'field': 'italic', 'stored': False, |
| 47 | 'native': True, 'characters': 1, 'positions': [1]}]) |
| 48 | |
| 49 | def test_partial_black_omission_is_reported_not_normalized_away(self): |
| 50 | node = {'format': {}, 'kind': {'text': 'ABA', 'paragraph_style': None, 'runs': [ |
| 51 | {'start': 0, 'end': 1, 'format': None}, {'start': 1, 'end': 2, 'format': 'black'}, |
| 52 | {'start': 2, 'end': 3, 'format': None}, |
| 53 | ]}} |
| 54 | space = {'nodes': {'black': {'format': {'highlight': 0}}}} |
| 55 | _, differences = compare_formats(space, [node], [[(c, {'highlight': 'automatic'}) for c in 'ABA']]) |
| 56 | self.assertEqual(differences, [{'paragraph': 0, 'field': 'highlight', 'stored': '#000000', |
| 57 | 'native': 'automatic', 'characters': 1, 'positions': [1]}]) |
| 58 | |
| 59 | |
| 60 | if __name__ == '__main__': |
| 61 | unittest.main() |