| 1 | """Compare library discovery with retained native OneNote hierarchy captures.""" |
| 2 | import json |
| 3 | import os |
| 4 | from pathlib import Path |
| 5 | import subprocess |
| 6 | import unittest |
| 7 | import xml.etree.ElementTree as ET |
| 8 | |
| 9 | ROOT = Path(__file__).resolve().parent.parent |
| 10 | |
| 11 | |
| 12 | class NativeDiscovery(unittest.TestCase): |
| 13 | def test_native_hierarchies(self): |
| 14 | fixtures = ['m6/native-features-01', 'native-encrypted/cold-encrypted-02', |
| 15 | 'native-delete/cold-deletion-05', 'native-external-assets'] |
| 16 | if os.environ.get('ONESTORE_NOTEBOOK_NATIVE'): |
| 17 | fixtures.append(str(Path(os.environ['ONESTORE_NOTEBOOK_NATIVE']).resolve())) |
| 18 | for fixture in fixtures: |
| 19 | with self.subTest(fixture=fixture): |
| 20 | source = ROOT / 'corpus' / fixture |
| 21 | catalog = json.loads(subprocess.check_output( |
| 22 | [str(ROOT / 'target/debug/examples/discover'), str(source / 'notebook')])) |
| 23 | hierarchy = ET.parse(source / 'read/hierarchy.xml').getroot() |
| 24 | notebook = next(node for node in hierarchy.iter() if node.tag.endswith('}Notebook')) |
| 25 | |
| 26 | def path(value): |
| 27 | return '/'.join(part for part in value.replace('\\', '/').split('/') if part) |
| 28 | |
| 29 | prefix = path(notebook.get('path')) |
| 30 | |
| 31 | def native(node): |
| 32 | sections = [] |
| 33 | groups = [] |
| 34 | for child in node: |
| 35 | if child.tag.endswith('}Section'): |
| 36 | relative = path(child.get('path'))[len(prefix) + 1:] |
| 37 | name = child.get('name') |
| 38 | if Path(relative).parts[-2:] == ('OneNote_RecycleBin', 'OneNote_DeletedPages.one'): |
| 39 | self.assertEqual(name, 'Deleted Pages') |
| 40 | name = 'OneNote_DeletedPages' |
| 41 | sections.append((relative, name)) |
| 42 | elif child.tag.endswith('}SectionGroup'): |
| 43 | groups.append(native(child)) |
| 44 | return {'path': path(node.get('path'))[len(prefix) + 1:], 'sections': sections, 'groups': groups} |
| 45 | |
| 46 | def actual(folder): |
| 47 | sections = [] |
| 48 | for section in folder['sections']: |
| 49 | state = section['state'] |
| 50 | name = state.get('Readable', {}).get('name') if isinstance(state, dict) else None |
| 51 | sections.append((section['path'], Path(section['path']).stem if name is None else name)) |
| 52 | return {'path': folder['path'], 'sections': sections, |
| 53 | 'groups': [actual(group) for group in folder['groups']]} |
| 54 | |
| 55 | self.assertEqual(actual(catalog), native(notebook)) |
| 56 | if fixture == 'm6/native-features-01': |
| 57 | self.assertEqual(len(catalog['toc']['unresolved']), 1) |
| 58 | self.assertEqual(catalog['toc']['unresolved'][0]['filename'], 'synthetic.one') |
| 59 | elif fixture == 'native-encrypted/cold-encrypted-02': |
| 60 | states = {section['path']: section['state'] for section in catalog['sections']} |
| 61 | self.assertEqual(states['synthetic.one'], 'Locked') |
| 62 | self.assertEqual(states['Open Notebook.one']['Unreadable']['message'], |
| 63 | 'Object space has no revision manifest list') |
| 64 | |
| 65 | |
| 66 | if __name__ == '__main__': |
| 67 | unittest.main() |