| 1 | import html |
| 2 | import json |
| 3 | import re |
| 4 | from pathlib import Path |
| 5 | import runpy |
| 6 | import shutil |
| 7 | from tempfile import TemporaryDirectory |
| 8 | import unittest |
| 9 | import xml.etree.ElementTree as ET |
| 10 | |
| 11 | from native_xml import ns |
| 12 | |
| 13 | ROOT = Path(__file__).resolve().parent.parent |
| 14 | FIXTURE = ROOT / 'corpus/link-edit' |
| 15 | compare = runpy.run_path(str(ROOT / 'tools/verify-document.py'))['compare'] |
| 16 | |
| 17 | |
| 18 | class LinkEditTest(unittest.TestCase): |
| 19 | def test_a_rust_hyperlink_renders_natively(self): |
| 20 | with TemporaryDirectory() as temporary: |
| 21 | read = Path(temporary) / 'read' |
| 22 | shutil.copytree(FIXTURE / 'cold/read', read) |
| 23 | compare(FIXTURE / 'candidate', read) |
| 24 | page, = (ET.parse(path).getroot() for path in sorted((FIXTURE / 'cold/read').glob('page-*.xml'))) |
| 25 | texts = [oe.find('one:T', ns).text for oe in page.iter('{%s}OE' % ns['one']) if oe.find('one:T', ns) is not None] |
| 26 | self.assertEqual([' '.join(text.split()) for text in texts], |
| 27 | ['Read about Rust <a href="https://example.invalid/rust">the Rust site</a>']) |
| 28 | |
| 29 | def test_onenote_links_between_pages_use_stored_identities(self): |
| 30 | with TemporaryDirectory() as temporary: |
| 31 | read = Path(temporary) / 'read' |
| 32 | shutil.copytree(FIXTURE / 'native-links/read', read) |
| 33 | compare(FIXTURE / 'native-links/notebook', read) |
| 34 | links = json.loads((FIXTURE / 'native-links/links.json').read_text(encoding='utf-8-sig')) |
| 35 | page, = (ET.parse(path).getroot() for path in sorted((FIXTURE / 'native-links/read').glob('page-*.xml')) |
| 36 | if ET.parse(path).getroot().get('name') == 'Read about Rust the Rust site') |
| 37 | hrefs = re.findall(r'href="([^"]*)"', ''.join(oe.find('one:T', ns).text for oe in page.iter('{%s}OE' % ns['one']) if oe.find('one:T', ns) is not None)) |
| 38 | section = re.search(r'section-id=(\{[^}]*\})', links['page']).group(1) |
| 39 | page_id = re.search(r'page-id=(\{[^}]*\})', links['page']).group(1) |
| 40 | self.assertEqual(hrefs[1], 'onenote:#Link%%20target&amp;section-id=%s&amp;page-id=%s&amp;end&amp;base-path=C:\\one-tests\\runs\\capture\\notebook\\links.one' % (section, page_id)) |
| 41 | self.assertEqual(hrefs[3], 'onenote:#section-id=%s&amp;end&amp;base-path=C:\\one-tests\\runs\\capture\\notebook\\links.one' % section) |
| 42 | |
| 43 | def test_rust_internal_links_render_natively(self): |
| 44 | with TemporaryDirectory() as temporary: |
| 45 | read = Path(temporary) / 'read' |
| 46 | shutil.copytree(FIXTURE / 'internal/cold/read', read) |
| 47 | compare(FIXTURE / 'internal/candidate', read) |
| 48 | pages = {ET.parse(path).getroot().get('name'): ET.parse(path).getroot() for path in sorted((FIXTURE / 'internal/cold/read').glob('page-*.xml'))} |
| 49 | page = next(page for name, page in pages.items() if name.startswith('Linking page')) |
| 50 | text = ' '.join(' '.join(oe.find('one:T', ns).text.split()) for oe in page.iter('{%s}OE' % ns['one']) if oe.find('one:T', ns) is not None) |
| 51 | self.assertRegex(text, r'^Linking page <a href="onenote:#Link%20target&amp;section-id=\{[0-9A-F-]{36}\}&amp;page-id=\{[0-9A-F-]{36}\}&amp;end&amp;base-path=C:\\one-tests\\runs\\capture\\notebook\\links.one">Link target</a>$') |
| 52 | |
| 53 | def test_onenote_links_typed_urls_and_dialog_addresses(self): |
| 54 | """OneNote 2010's read of `native-typed`: a typed `www.` address opens over http, |
| 55 | and a Link dialog address typed without a scheme does too.""" |
| 56 | text = (FIXTURE / 'native-typed/read/page-000.xml').read_text(encoding='utf-8-sig') |
| 57 | hrefs = [html.unescape(href) for href in re.findall(r'href="([^"]*)"', text)] |
| 58 | self.assertEqual(hrefs[1], 'http://www.example.com') |
| 59 | self.assertEqual(hrefs[11], 'http://www.d.example') |
| 60 | self.assertEqual(hrefs[15], 'http://example.net/x') |
| 61 | self.assertNotIn('me@example.com', hrefs) |
| 62 | |
| 63 | def test_editor_links_and_equations_render_natively(self): |
| 64 | """What the canvas editor saved for typed URLs, the Link dialog, Remove Link and |
| 65 | equations typed after Alt+= reads back in a cold OneNote 2010 with the links and |
| 66 | MathML it meant (`crates/canvas/tests/links_equations.rs`).""" |
| 67 | row = FIXTURE / 'editor' |
| 68 | with TemporaryDirectory() as temporary: |
| 69 | read = Path(temporary) / 'read' |
| 70 | shutil.copytree(row / 'cold/read', read) |
| 71 | compare(row / 'candidate', read) |
| 72 | expected = json.loads((row / 'expected.json').read_text()) |
| 73 | path = next(path for path in sorted((row / 'cold/read').glob('page-*.xml')) |
| 74 | if ET.parse(path).getroot().get('name').startswith('Linking page')) |
| 75 | page = ET.parse(path).getroot() |
| 76 | text = ''.join(oe.find('one:T', ns).text for oe in page.iter('{%s}OE' % ns['one']) if oe.find('one:T', ns) is not None) |
| 77 | hrefs = [html.unescape(href) for href in re.findall(r'href="([^"]*)"', text)] |
| 78 | self.assertEqual(hrefs, expected['hrefs']) |
| 79 | raw = path.read_text(encoding='utf-8-sig') |
| 80 | mathml = [re.sub(r'&#(\d+);', lambda m: chr(int(m.group(1))), body) |
| 81 | for body in re.findall(r'<mml:math[^>]*>(.*?)</mml:math>', raw, re.S)] |
| 82 | self.assertEqual(mathml, expected['mathml']) |
| 83 | |
| 84 | |
| 85 | if __name__ == '__main__': |
| 86 | unittest.main() |