#!/usr/bin/env python3 """Generate deterministic, project-authored HTML/ZIP/EPUB acceptance fixtures.""" from pathlib import Path import hashlib import json import zipfile ROOT = Path(__file__).resolve().parent / "fixtures" / "web" ROOT.mkdir(parents=True, exist_ok=True) def write(path, data): target = ROOT / path target.parent.mkdir(parents=True, exist_ok=True) target.write_bytes(data.encode("utf-8") if isinstance(data, str) else data) def archive(name, entries): with zipfile.ZipFile(ROOT / name, "w") as output: for path, content in entries.items(): info = zipfile.ZipInfo(path, (2026, 1, 1, 0, 0, 0)) info.create_system = 3 info.external_attr = 0o100600 << 16 output.writestr(info, content, compress_type=zipfile.ZIP_STORED if path == "mimetype" else zipfile.ZIP_DEFLATED) style = "body{font-family:serif;margin:32px;line-height:1.6;color:#16293a}h1{border-bottom:3px solid #147d79}section{min-height:720px}.hidden{display:none}nav{background:#eef8f8;padding:16px}" svg = 'Local SVG' html = """DocView local document

文書リーダー検証 / Local document

Local asset

第一節

日本語、Latin, 漢字かんじ。This is locally authored acceptance text.

第二節

同じ文書内の資源とアンカーを検証します。

ARIA見出し

先頭へ戻る

""" write("html/index.html", html) write("html/assets/style.css", style) write("html/assets/local.svg", svg) write("html/next.html", 'Second resource

別HTML

第二節へ戻る') write("html/vertical.html", '

縦書き第一節

縦書きの読書方向と物理スクロールを分けて検証する。

縦書き第二節

章内進捗は右から左へ増加する。

') write("html/security.html", """Static security fixture

Static security fixture

SCRIPT DID NOT RUN

Blocked fileBlocked other session Explicit external link""") entries = {"book/index.html": html, "book/assets/style.css": style, "book/assets/local.svg": svg, "book/next.html": (ROOT / "html/next.html").read_text()} archive("html-book.zip", entries) archive("html-entry-choice.zip", {"one.html": "

One

", "two.html": "

Two

"}) archive("unsafe-traversal.zip", {"../outside.html": "

Must not extract

"}) container = '' package = '''DocView EPUB verificationurn:uuid:docview-fixtureja''' nav = '''目次''' chapter = lambda title, anchor: f'{title}

{title}

著者指定の本文とルビを表示します。読書どくしょ。

章内の見出し

Static chapter content.

' epub = {"mimetype": "application/epub+zip", "META-INF/container.xml": container, "OPS/package.opf": package, "OPS/nav.xhtml": nav, "OPS/first.xhtml": chapter("第一章", "p1"), "OPS/second.xhtml": chapter("第二章", "p2"), "OPS/extra.xhtml": chapter("補遺", "extra"), "OPS/style.css": style} archive("reflow-rtl.epub", epub) fixed = dict(epub) fixed["OPS/package.opf"] = package.replace('', 'pre-paginated').replace('', '') fixed["OPS/first.xhtml"] = 'Fixed page

Fixed layout 900 × 650

Second chapter switches to reflow.

' archive("fixed-mixed.epub", fixed) epub2 = dict(epub) epub2["OPS/package.opf"] = package.replace('version="3.0"', 'version="2.0"').replace('', '') epub2["OPS/nav.xhtml"] = '