1from pathlib import Path
2import hashlib
3import json
4import runpy
5import shutil
6from tempfile import TemporaryDirectory
7import unittest
8import xml.etree.ElementTree as ET
9
10from native_xml import ns
11
12ROOT = Path(__file__).resolve().parent.parent
13FIXTURE = ROOT / 'corpus/custom-art'
14compare = runpy.run_path(str(ROOT / 'tools/verify-document.py'))['compare']
15
16
17def tagged(read):
18 """The page's tagged paragraphs: text, then each tag as (name, symbol, completed)."""
19 page = ET.parse(read / 'page-000.xml').getroot()
20 definitions = {d.get('index'): (d.get('name'), int(d.get('symbol'))) for d in page.findall('one:TagDef', ns)}
21 return [((oe.find('one:T', ns).text or ''),
22 [definitions[tag.get('index')] + (tag.get('completed'),) for tag in oe.findall('one:Tag', ns)])
23 for oe in page.iter('{%s}OE' % ns['one']) if oe.find('one:Tag', ns) is not None]
24
25
26class CustomArtTest(unittest.TestCase):
27 def test_tags_with_art_cold_open_with_their_fallback_symbols(self):
28 with TemporaryDirectory() as temporary:
29 read = Path(temporary) / 'read'
30 shutil.copytree(FIXTURE / 'cold/before-read', read)
31 compare(FIXTURE / 'candidate', read)
32 self.assertEqual(tagged(FIXTURE / 'cold/before-read'), [
33 ('Launch day', [('Launch', 13, 'true')]),
34 ('Ship the release', [('Ship it', 127, 'true')]),
35 ('Checked off', [('Done', 3, 'true')]),
36 ('Plain OneNote tag', [('Important', 13, 'true')]),
37 ])
38
39 def test_onenote_editing_the_page_keeps_the_mapping_and_the_folder(self):
40 edited = tagged(FIXTURE / 'cold/read')
41 self.assertEqual([text for text, _ in edited][:1], ['Launch day, moved to Friday'])
42 self.assertEqual(edited[2][1], [('Done', 3, 'false')])
43 # Every tag the mapping names is still on the page under its name and symbol.
44 sidecar = FIXTURE / 'candidate/.snowbound'
45 mapped = {(m['name'], m['shape']): m['art'] for m in json.loads((sidecar / 'tags.json').read_text())}
46 stored = {tag[:2] for _, tags in edited for tag in tags}
47 self.assertEqual(set(mapped) - stored, set())
48 for art in mapped.values():
49 self.assertEqual(hashlib.sha256((sidecar / 'tags' / art).read_bytes()).hexdigest(), art.split('.')[0])
50 # OneNote kept the folder hidden, left no table of contents in it and changed none of it.
51 left = json.loads((FIXTURE / 'cold/sidecar.json').read_text(encoding='utf-8-sig'))
52 self.assertIn('Hidden', left['attributes'])
53 files = {f['path']: f['sha256'] for f in left['files'] if f['sha256']}
54 expected = {p.relative_to(sidecar).as_posix(): hashlib.sha256(p.read_bytes()).hexdigest()
55 for p in sidecar.rglob('*') if p.is_file()}
56 self.assertEqual(files, expected)
57 self.assertEqual(sorted(left['notebook']), ['.snowbound', 'Custom art.one', 'Open Notebook.onetoc2'])
58
59
60if __name__ == '__main__':
61 unittest.main()