#!/usr/bin/env python3 from __future__ import annotations import hashlib import struct import tempfile import unittest from pathlib import Path from unittest.mock import Mock, patch import package_windows_x64 import verify_windows_native def write_pe(path: Path, machine: int = verify_windows_native.PE_MACHINE_AMD64) -> None: data = bytearray(128) data[:2] = b"MZ" struct.pack_into(" str: lines = [f"DLL Name: {name}" for name in verify_windows_native.RUNTIME_DLLS] lines.extend(f"[ 0] {name}" for name in verify_windows_native.REQUIRED_EXPORTS) return "\n".join(lines) def make_export(root: Path) -> Path: export = root / "export" for relative in package_windows_x64.REQUIRED_FILES: path = export / relative path.parent.mkdir(parents=True, exist_ok=True) path.write_bytes(f"fixture:{relative}".encode()) write_pe(export / "Himegari.exe") managed = export / package_windows_x64.MANAGED_DIRECTORY for name in (verify_windows_native.SHIM, *verify_windows_native.RUNTIME_DLLS): write_pe(managed / name) return export class PackageWindowsX64Tests(unittest.TestCase): def test_verify_rejects_missing_linux_and_wrong_machine_files(self) -> None: with tempfile.TemporaryDirectory() as temporary: export = make_export(Path(temporary)) completed = Mock(returncode=0, stdout=objdump_text(), stderr="") with patch.object(verify_windows_native.subprocess, "run", return_value=completed): package_windows_x64.verify_export(export, "objdump") (export / package_windows_x64.REQUIRED_FILES[-1]).unlink() with self.assertRaisesRegex(ValueError, "missing"): package_windows_x64.verify_export(export, "objdump") (export / package_windows_x64.REQUIRED_FILES[-1]).write_bytes(b"restored") linux = export / package_windows_x64.MANAGED_DIRECTORY / "stale.so" linux.write_bytes(b"linux") with self.assertRaisesRegex(ValueError, "Linux-only"): package_windows_x64.verify_export(export, "objdump") linux.unlink() write_pe(export / "Himegari.exe", machine=0x014C) with self.assertRaisesRegex(ValueError, "not AMD64"): package_windows_x64.verify_export(export, "objdump") def test_package_has_notices_reports_checksums_and_deterministic_zip(self) -> None: with tempfile.TemporaryDirectory() as temporary: temporary_root = Path(temporary) export = make_export(temporary_root) output = temporary_root / "build/package/windows-x64" metadata = {"schema_version": 1, "source_commit": "fixture"} verification = {"schema_version": 1, "target": "win-x64"} with patch.object(package_windows_x64, "REPO", temporary_root), patch.object( package_windows_x64, "PROJECT_FILES", ("LICENSE", "THIRD_PARTY_NOTICES.md") ): (temporary_root / "LICENSE").write_text("MIT\n", encoding="utf-8") (temporary_root / "THIRD_PARTY_NOTICES.md").write_text( "notices\n", encoding="utf-8" ) package_windows_x64.create_package( export, output, metadata, verification, 123456789 ) archive = output / f"{package_windows_x64.PACKAGE_NAME}.zip" first = hashlib.sha256(archive.read_bytes()).hexdigest() package_root, archive = package_windows_x64.create_package( export, output, metadata, verification, 123456789 ) second = hashlib.sha256(archive.read_bytes()).hexdigest() self.assertEqual(first, second) self.assertTrue((package_root / "LICENSE").is_file()) self.assertTrue((package_root / "BUILD-INFO.json").is_file()) self.assertTrue((package_root / "WINDOWS-VERIFICATION.json").is_file()) checksums = (package_root / "SHA256SUMS").read_text(encoding="utf-8") self.assertIn("Himegari.exe", checksums) self.assertIn("THIRD_PARTY_NOTICES.md", checksums) if __name__ == "__main__": unittest.main()