sources/historical-doc-tests/test_contracts.py

Текстовый файл из учебного комплекта, не свидетельство установленного runtime. Вернуться к учебнику · Исходный файл

   1 """Проверки аудиоупаковки и структуры учебника. Реальной сети/браузера нет."""
   2 import base64
   3 import contextlib
   4 import email.policy
   5 from email.parser import BytesParser
   6 from html.parser import HTMLParser
   7 import html
   8 import importlib.util
   9 import io
  10 import json
  11 import hashlib
  12 from pathlib import Path
  13 import re
  14 import subprocess
  15 import tempfile
  16 import unittest
  17 from unittest.mock import patch
  18 from urllib.parse import unquote, urlparse
  19 import urllib.request
  20 import xml.etree.ElementTree as ET
  21 
  22 REPO = Path(__file__).resolve().parents[2]
  23 BOOK = REPO / "docs/codex-cli-voice-textbook.html"
  24 
  25 
  26 class Structure(HTMLParser):
  27     def __init__(self):
  28         super().__init__(convert_charrefs=True)
  29         self.ids, self.links, self.stack, self.rects, self.chapters = {}, [], [], [], []
  30         self.h1 = 0
  31     def handle_starttag(self, tag, attrs):
  32         attrs = dict(attrs)
  33         if "id" in attrs:
  34             if attrs["id"] in self.ids:
  35                 raise AssertionError("duplicate ID " + attrs["id"])
  36             self.ids[attrs["id"]] = attrs
  37         if tag == "a":
  38             self.links.append(attrs.get("href", ""))
  39         if tag == "h1": self.h1 += 1
  40         if "chapter" in attrs.get("class", "").split(): self.chapters.append(attrs["id"])
  41         if tag == "rect" and any(t == "figure" for t, _ in self.stack):
  42             self.rects.append(any(t == "a" and a.get("href", "").startswith("#") for t, a in self.stack))
  43         if tag == "img":
  44             src = attrs.get("src", "")
  45             if not src.startswith("data:image/png;base64,") or not attrs.get("alt"):
  46                 raise AssertionError("image must be embedded PNG with alt")
  47             data = base64.b64decode(src.split(",", 1)[1], validate=True)
  48             if not data.startswith(b"\x89PNG\r\n\x1a\n") or len(data) > 2_000_000:
  49                 raise AssertionError("invalid or oversized screenshot")
  50         if tag in ("script", "iframe", "link") and ("src" in attrs or "href" in attrs):
  51             raise AssertionError("external executable/asset")
  52         if tag not in ("meta", "br", "input", "hr", "link", "img"):
  53             self.stack.append((tag, attrs))
  54     def handle_startendtag(self, tag, attrs):
  55         self.handle_starttag(tag, attrs)
  56         if tag not in ("meta", "br", "input", "hr", "link", "img"):
  57             self.handle_endtag(tag)
  58     def handle_endtag(self, tag):
  59         if not self.stack or self.stack.pop()[0] != tag:
  60             raise AssertionError("unbalanced tag " + tag)
  61 
  62 
  63 class TextbookTests(unittest.TestCase):
  64     def setUp(self):
  65         self.source = BOOK.read_text()
  66         self.parsed = Structure()
  67         self.parsed.feed(self.source)
  68 
  69     def test_unique_ids_balanced_autonomous_and_original_anchors(self):
  70         self.assertFalse(self.parsed.stack)
  71         self.assertEqual(self.parsed.h1, 1)
  72         self.assertTrue({"overview", "cli", "protocols", "demo", "launch", "evidence"}.issubset(self.parsed.chapters))
  73         self.assertEqual(len(self.parsed.chapters), 29)
  74         self.assertIn("ui-entrypoints", self.parsed.chapters)
  75 
  76     def test_every_svg_block_is_real_anchor_and_paths_exist(self):
  77         self.assertTrue(self.parsed.rects)
  78         self.assertTrue(all(self.parsed.rects))
  79         for url in self.parsed.links:
  80             with self.subTest(url=url):
  81                 if url.startswith("#"):
  82                     self.assertIn(unquote(url[1:]), self.parsed.ids)
  83                 elif url.startswith("file:"):
  84                     self.assertTrue(Path(unquote(urlparse(url).path)).exists(), url)
  85                 else:
  86                     if url.startswith("https://"):
  87                         continue
  88                     self.assertFalse(urlparse(url).scheme, url)
  89                     target = (BOOK.parent / unquote(urlparse(url).path)).resolve()
  90                     self.assertTrue(target.is_file(), url)
  91                     if target.suffix == ".html" and urlparse(url).fragment:
  92                         parsed = Structure()
  93                         parsed.feed(target.read_text())
  94                         self.assertIn(unquote(urlparse(url).fragment), parsed.ids)
  95 
  96     def test_js_syntax_and_shell_command_blocks(self):
  97         scripts = re.findall(r"<script>(.*?)</script>", self.source, re.S)
  98         self.assertEqual(len(scripts), 1)
  99         result = subprocess.run(["env", "-u", "NODE_OPTIONS", "node", "--check"], input=scripts[0], text=True, capture_output=True)
 100         self.assertEqual(result.returncode, 0, result.stderr)
 101         commands = re.findall(r'<pre><code class="language-bash"[^>]*>(.*?)</code></pre>', self.source, re.S)
 102         self.assertGreaterEqual(len(commands), 14)
 103         for command in commands:
 104             result = subprocess.run(["bash", "-n"], input=html.unescape(re.sub('<[^>]+>', '', command)), text=True, capture_output=True)
 105             self.assertEqual(result.returncode, 0, result.stderr)
 106 
 107     def test_svg_xml_and_two_schemes_per_audio_method(self):
 108         diagrams = [svg for svg in re.findall(r"<svg\b.*?</svg>", self.source, re.S) if 'role="img"' in svg]
 109         self.assertGreaterEqual(len(diagrams), 20)
 110         for svg in diagrams:
 111             ET.fromstring(svg)
 112         for chapter in ["demo", "stt-http", "tts-http", "tts-read-aloud", "tts-realtime", "tts-appserver", "tts-local", "voice-console"]:
 113             match = re.search(r'<section id="' + chapter + r'".*?</section>', self.source, re.S)
 114             self.assertGreaterEqual(match[0].count('<figure'), 2, chapter)
 115 
 116     def test_entrypoint_page_navigation_screenshots_and_code_map(self):
 117         page = BOOK
 118         source = self.source
 119         parsed = Structure()
 120         parsed.feed(source)
 121         self.assertFalse(parsed.stack)
 122         self.assertEqual(parsed.h1, 1)
 123         self.assertTrue(all(parsed.rects))
 124         parsed_files={page.resolve():parsed}
 125         for url in parsed.links:
 126             parts = urlparse(url)
 127             if parts.scheme == "https":
 128                 continue
 129             self.assertFalse(parts.scheme, url)
 130             target = page if not parts.path else (page.parent / unquote(parts.path)).resolve()
 131             self.assertTrue(target.is_file(), url)
 132             if target.suffix == ".html" and parts.fragment:
 133                 if target not in parsed_files:
 134                     target_parsed = Structure()
 135                     target_parsed.feed(target.read_text())
 136                     parsed_files[target]=target_parsed
 137                 target_parsed=parsed_files[target]
 138                 self.assertIn(unquote(parts.fragment), target_parsed.ids, url)
 139         self.assertIn('href="audio-ui-entrypoints.html#mic"', self.source)
 140         self.assertIn('href="#ui-entrypoints"', source)
 141         for svg in re.findall(r"<svg\b.*?</svg>", source, re.S):
 142             ET.fromstring(svg)
 143         for _, block in re.findall(r'<div class="example" data-demo="([^"]+)">.*?<pre><code[^>]*>(.*?)</code></pre>', source, re.S):
 144             check = subprocess.run(["bash", "-n"], input=html.unescape(re.sub('<[^>]+>', '', block)), text=True, capture_output=True)
 145             self.assertEqual(check.returncode, 0, check.stderr)
 146 
 147     def test_screenshot_provenance_and_embedded_pixels(self):
 148         folder = REPO / "docs/audio-ui-assets"
 149         manifest = json.loads((folder / "screenshots.json").read_text())
 150         page = self.source
 151         embedded = {base64.b64decode(value, validate=True) for value in re.findall(r'src="data:image/png;base64,([^"]+)"', page)}
 152         self.assertEqual(len(embedded), 3)
 153         for item in manifest["images"]:
 154             data = (folder / item["file"]).read_bytes()
 155             self.assertEqual(hashlib.sha256(data).hexdigest(), item["sha256"])
 156             self.assertIn(data, embedded)
 157             self.assertEqual(int.from_bytes(data[16:20], "big"), item["width"])
 158             self.assertEqual(int.from_bytes(data[20:24], "big"), item["height"])
 159         self.assertIn("not proof of Community fork", manifest["scope"])
 160         evidence = json.loads((folder / "bundle-code-map.json").read_text())
 161         self.assertEqual(len(evidence["entries"]), 11)
 162         self.assertTrue(all(e["offset"] >= 0 for e in evidence["entries"]))
 163 
 164 
 165 class ContractTests(unittest.TestCase):
 166     def run_bash_python_payload(self, filename, data):
 167         # Выполняем именно вложенный Python из Bash. Сетевой opener заменён
 168         # перехватчиком: пакет до сервера не отправляется.
 169         script = (REPO / "scripts/voice-probes/chatgpt-transcribe.sh").read_text().split("<<'PY'\n", 1)[1].rsplit("\nPY", 1)[0]
 170         seen = []
 171         class Response(io.BytesIO):
 172             def __enter__(self): return self
 173             def __exit__(self, *args): self.close()
 174         class Opener:
 175             def open(self, request, timeout):
 176                 seen.append(request)
 177                 return Response(b'{"text":"synthetic transcript"}')
 178         with tempfile.TemporaryDirectory() as folder:
 179             root = Path(folder)
 180             path = root / filename
 181             path.write_bytes(data)
 182             auth = root / "auth.json"
 183             auth.write_text(json.dumps({"auth_mode": "chatgpt", "tokens": {"access_token": "synthetic-token", "account_id": "own"}}))
 184             output = io.StringIO()
 185             with patch("sys.argv", ["-", str(path), str(auth)]), patch.object(urllib.request, "build_opener", return_value=Opener()), contextlib.redirect_stdout(output):
 186                 exec(compile(script, "chatgpt-transcribe.sh", "exec"), {"__name__": "__main__"})
 187             self.assertEqual(output.getvalue().strip(), "synthetic transcript")
 188         request = seen[0]
 189         mime = request.get_header("Content-type")
 190         envelope = BytesParser(policy=email.policy.default).parsebytes(("Content-Type: " + mime + "\r\n\r\n").encode() + request.data)
 191         return request, list(envelope.iter_parts())
 192 
 193     def test_bash_multipart_contains_exact_flac_no_metadata_or_base64(self):
 194         data = b"fLaC" + bytes(range(256))
 195         request, parts = self.run_bash_python_payload("probe.flac", data)
 196         self.assertEqual(request.get_method(), "POST")
 197         self.assertEqual(request.full_url, "https://chatgpt.com/backend-api/transcribe")
 198         self.assertEqual(len(parts), 1)
 199         self.assertEqual(parts[0].get_param("name", header="content-disposition"), "file")
 200         self.assertEqual(parts[0].get_content_type(), "audio/flac")
 201         self.assertEqual(parts[0].get_payload(decode=True), data)
 202         self.assertNotIn("synthetic-token", request.full_url)
 203 
 204     def test_mime_mismatch_rejected_before_send(self):
 205         # Локальная сигнатура известного контейнера; это не проверка сервера
 206         # и не полное декодирование повреждённых фреймов внутри контейнера.
 207         for bytes_ in [b"ID3-not-flac", b"RIFF-not-flac"]:
 208             with contextlib.redirect_stderr(io.StringIO()), self.assertRaises(SystemExit):
 209                 self.run_bash_python_payload("wrong.flac", bytes_)
 210 
 211     def test_raw_pcm_rate_is_external_metadata_not_self_describing(self):
 212         pcm = b"\x01\x00" * 24000
 213         self.assertEqual(len(pcm) / (24000 * 1 * 2), 1)
 214         self.assertEqual(len(pcm) / (48000 * 1 * 2), .5)
 215         self.assertEqual(base64.b64decode(base64.b64encode(pcm), validate=True), pcm)
 216         with self.assertRaises(ValueError):
 217             base64.b64decode("!invalid", validate=True)
 218 
 219 
 220 if __name__ == "__main__":
 221     unittest.main()