"""Validate real UI exports; run from ute2e. No authentication data is read.""" from pathlib import Path import struct import json import zipfile import xml.etree.ElementTree as ET from pypdf import PdfReader root = Path('reports/guide-closure-20260910') checks = [] def check(name, passed, detail=''): checks.append(dict(name=name, status='PASS' if passed else 'FAIL', detail=detail)) pdf = PdfReader(root / 'export-pdf.pdf') check('PDF 四页可解析且每页含文本', len(pdf.pages) == 4 and all(p.extract_text().strip() for p in pdf.pages), f'{len(pdf.pages)} pages') with zipfile.ZipFile(root / 'export-ofd.ofd') as z: xmls = [n for n in z.namelist() if n.lower().endswith('.xml')] for name in xmls: ET.fromstring(z.read(name)) check('OFD ZIP 完整、入口和 XML 可解析', z.testzip() is None and 'OFD.xml' in z.namelist() and len(xmls) > 4, f'{len(xmls)} XML files; 未使用第三方 OFD 阅读器认证') with zipfile.ZipFile(root / 'export-offline.zip') as z: names = z.namelist() check('离线 ZIP 完整', z.testzip() is None, f'{len(names)} files') scripts = [z.read(n) for n in names if n.endswith(('.js', '.html'))] check('离线脚本没有 Vite 开发缓存引用', not any(b'/.vite-cache/' in s or b'/node_modules/.pnpm/' in s for s in scripts)) glbs = [z.read(n) for n in names if n.lower().endswith('.glb')] originals = [Path('../../文档/素材') / n for n in ['09-Fox.glb', '08-CesiumMilkTruck.glb']] def structure(b): assert b[:4] == b'glTF' and struct.unpack_from('