tests/test_macos_media.py
Rama master · réplica de lectura del repositorio original.
"""macOS 媒体分发的清单、架构及源码校验。"""
from __future__ import annotations
import json
from pathlib import Path
import sys
import tempfile
import unittest
from unittest.mock import patch
from scripts import media_tool_bundle
SCRIPTS = Path(__file__).resolve().parents[1] / "scripts"
class MacMediaBundleTests(unittest.TestCase):
def setUp(self):
directory = tempfile.TemporaryDirectory()
self.addCleanup(directory.cleanup)
self.root = Path(directory.name).resolve()
def fixture(self, tool, architecture="arm64"):
root = self.root / tool
root.mkdir()
required, sources, license_name = media_tool_bundle.POLICIES[tool]
for name in required:
path = root / name.removesuffix(".exe")
path.parent.mkdir(exist_ok=True, parents=True)
path.write_bytes(b"fixture")
archive = self.root / f"{tool}-macos-{architecture}-corresponding-source.zip"
archive.write_bytes(b"source")
manifest = {"version": "fixed", "platform": "darwin", "architecture": architecture,
"license": license_name,
"files": {path.relative_to(root).as_posix(): media_tool_bundle.digest(path)
for path in root.rglob("*") if path.is_file()},
"sources": [{"name": name, "revision": "fixed", "url": "https://example.org/source",
"sha256": "1" * 64} for name in sources],
"source_archive": {"name": archive.name, "sha256": media_tool_bundle.digest(archive)}}
(root / "manifest.json").write_text(json.dumps(manifest))
return root, archive
def test_both_tools_require_matching_architecture_and_complete_sources(self):
for tool in ("ffmpeg", "untrunc"):
with self.subTest(tool=tool):
root, archive = self.fixture(tool)
manifest, source = media_tool_bundle.validate(root, tool, architecture="arm64")
self.assertEqual(source, archive)
self.assertEqual(manifest["architecture"], "arm64")
with self.assertRaisesRegex(ValueError, "架构"):
media_tool_bundle.validate(root, tool, architecture="x86_64")
with self.assertRaises(ValueError):
media_tool_bundle.validate(root, tool)
archive.write_bytes(b"modified")
with self.assertRaisesRegex(ValueError, "SHA-256"):
media_tool_bundle.validate(root, tool, architecture="arm64")
def test_binary_audit_rejects_non_system_libraries(self):
with patch.object(sys, "path", [str(SCRIPTS), *sys.path]):
from scripts import build_macos_media
for dependency, valid in (("/usr/lib/libSystem.B.dylib", True),
("/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia", True),
("/opt/homebrew/opt/x264/lib/libx264.dylib", False),
("@rpath/libavcodec.dylib", False)):
with self.subTest(dependency=dependency), patch.object(build_macos_media.subprocess, "run"), \
patch.object(build_macos_media.subprocess, "check_output",
return_value=f"binary:\n\t{dependency} (compatibility version 1.0.0)\n"):
if valid:
build_macos_media.audit_binary(self.root / "binary", "arm64")
else:
with self.assertRaisesRegex(ValueError, "非系统"):
build_macos_media.audit_binary(self.root / "binary", "arm64")
def test_cloudflared_validation_checks_archive_and_binary_hashes(self):
with patch.object(sys, "path", [str(SCRIPTS), *sys.path]):
from scripts import fetch_cloudflared_macos
source = {"url": "https://example.org/cloudflared.tgz", "sha256": ""}
files = ("cloudflared", "LICENSE-cloudflared.txt", "NOTICE-cloudflared.md")
for name in (*files, "cloudflared.tgz"):
(self.root / name).write_bytes(b"fixture")
source["sha256"] = media_tool_bundle.digest(self.root / "cloudflared.tgz")
manifest = {"version": "fixed", "architecture": "arm64", "source": source,
"files": {name: media_tool_bundle.digest(self.root / name) for name in files}}
(self.root / "manifest.json").write_text(json.dumps(manifest))
lock = {"version": "fixed", "assets": {"arm64": source}}
load = fetch_cloudflared_macos.json.loads
def loads(text):
return lock if '"assets"' in text else load(text)
with patch.object(fetch_cloudflared_macos.json, "loads", side_effect=loads), \
patch.object(fetch_cloudflared_macos, "audit_binary"):
self.assertEqual(fetch_cloudflared_macos.validate(self.root, "arm64"), manifest)
(self.root / "cloudflared").write_bytes(b"tampered")
with self.assertRaisesRegex(ValueError, "SHA-256"):
fetch_cloudflared_macos.validate(self.root, "arm64")
@unittest.skipIf(sys.platform == "win32", "macOS 工具使用 POSIX 文件名")
def test_macos_resolvers_find_the_executable_siblings_without_path_tools(self):
from peach.ffmpeg import FFmpegResolver
from peach.mp4recover import untrunc_path
from peach.tunnel import resolve_binary
executable = self.root / "Peach.app/Contents/MacOS/Peach"
for name in ("tools/ffmpeg/bin/ffmpeg", "tools/ffmpeg/bin/ffprobe", "tools/untrunc/untrunc", "cloudflared"):
path = (executable.parent.parent / "Resources" / name if name.startswith("tools/")
else executable.parent / name)
path.parent.mkdir(exist_ok=True, parents=True)
path.write_bytes(b"fixture")
# 应用包布局只在 macOS 生效,Linux runner 上按 macOS 解析同一套 POSIX 文件名。
with patch.object(sys, "executable", str(executable)), patch.object(sys, "frozen", True, create=True), \
patch.object(sys, "platform", "darwin"), patch.dict("os.environ", {"PATH": ""}, clear=True):
resolver = FFmpegResolver(self.root / "missing")
self.assertEqual(resolver.ffmpeg().source, "peach-bundled")
self.assertEqual(resolver.ffprobe().path, executable.parent.parent / "Resources/tools/ffmpeg/bin/ffprobe")
self.assertEqual(untrunc_path(self.root / "missing"), executable.parent.parent / "Resources/tools/untrunc/untrunc")
self.assertEqual(resolve_binary(), executable.parent / "cloudflared")