1#!/usr/bin/env python3
2"""Compare a Rust scale fixture against its generator and fresh native capture."""
3import argparse
4import hashlib
5import json
6from pathlib import Path, PureWindowsPath
7import subprocess
8import xml.etree.ElementTree as ET
9
10from document_model import EXPORTER, ordered_pages, walk
11from native_xml import ns, pages, texts, project_text
12
13ROOT = Path(__file__).resolve().parent.parent
14
15
16def compare(source, capture):
17 expected = json.loads((source / 'expected.json').read_text())
18 manifest = {row['path']: row for row in json.loads((capture / 'source.json').read_text())}
19 for name, row in manifest.items():
20 assert hashlib.sha256((source / 'notebook' / name).read_bytes()).hexdigest() == row['sha256'], 'Source changed since native capture'
21 hierarchy = ET.parse(capture / 'read/hierarchy.xml').getroot()
22 sections = hierarchy.findall('.//one:Section', ns)
23 order = [PureWindowsPath(section.get('path')).name for section in sections]
24 assert order == [row['section'] for row in reversed(expected)], 'Native section order differs from the generated reverse order'
25 native = {page.get('ID'): page for page in pages(capture / 'read')}
26 section_pages = {PureWindowsPath(section.get('path')).name: section.findall('one:Page', ns) for section in sections}
27 for row in expected:
28 output = subprocess.check_output([EXPORTER, source / 'notebook' / row['section']])
29 document = json.loads(output)
30 (_, _, space, oid), = ordered_pages(document)
31 actual = [node['kind']['text'] for _, node in walk(space, oid) if node['kind']['type'] == 'RichText']
32 assert actual == [row['text']], (row['section'], 'Rust text differs from generator input')
33 page, = section_pages[row['section']]
34 assert texts(native[page.get('ID')]) == [project_text(row['text'])], (row['section'], 'Native text differs from generator input')
35 print(f'Passed {len(expected)} sections and {sum(len(row["text"]) for row in expected):,} Unicode scalars against the independent generator input; reverse section order survived native import.')
36
37
38if __name__ == '__main__':
39 parser = argparse.ArgumentParser(description=__doc__)
40 parser.add_argument('source', type=Path)
41 parser.add_argument('capture', type=Path)
42 args = parser.parse_args()
43 compare(args.source, args.capture)