import tarfile
import tempfile
import unittest
import zipfile
from pathlib import Path
from unittest.mock import patch
from scripts.verify_release_package import (
ReleasePackageVerificationError,
VerificationConfig,
_run_smoke_command,
main,
verify_release_package,
)
def write_text(path: Path, text: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding="utf-8")
def create_package_tree(root: Path, *, binary_name: str = "neser") -> Path:
package_root = root / "neser"
write_text(package_root / "assets/fonts/NunitoSans-Regular.ttf", "font\n")
write_text(package_root / "gamecontrollerdb.txt", "controller mappings\n")
write_text(package_root / "neser.conf.example", "# config\n")
write_text(package_root / "README.md", "# neser\n")
write_text(package_root / "README-NES.md", "# nes\n")
write_text(package_root / "README-GB.md", "# gb\n")
write_text(package_root / "README-GBA.md", "# gba\n")
write_text(package_root / "LICENSE", "license\n")
write_text(package_root / "shaders/stock.slangp", "shader0 = stock.slang\n")
write_text(package_root / "shaders/stock.slang", "void main() {}\n")
binary_path = package_root / binary_name
write_text(binary_path, "#!/bin/sh\nprintf 'neser 1.0.0\\n'\n")
binary_path.chmod(0o755)
return package_root
def create_tar_gz(package_root: Path, archive_path: Path) -> None:
with tarfile.open(archive_path, "w:gz") as archive:
archive.add(package_root, arcname="neser")
def create_zip(package_root: Path, archive_path: Path) -> None:
with zipfile.ZipFile(archive_path, "w") as archive:
for path in sorted(package_root.rglob("*")):
if path.is_file():
archive.write(path, Path("neser") / path.relative_to(package_root))
class VerifyReleasePackageTests(unittest.TestCase):
def test_verify_tar_gz_package_accepts_required_layout_and_smoke_command(
self,
) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)
package_root = create_package_tree(temp_dir / "src")
archive_path = temp_dir / "neser-linux-x86_64.tar.gz"
create_tar_gz(package_root, archive_path)
verify_release_package(
VerificationConfig(
archive_path=archive_path,
binary_name="neser",
smoke_command=["./neser", "--version"],
require_unix_executable=True,
)
)
def test_verify_zip_package_accepts_required_windows_layout(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)
package_root = create_package_tree(
temp_dir / "src", binary_name="neser.exe"
)
archive_path = temp_dir / "neser-windows-x86_64.zip"
create_zip(package_root, archive_path)
verify_release_package(
VerificationConfig(
archive_path=archive_path,
binary_name="neser.exe",
)
)
def test_verify_package_reports_missing_required_resource(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)
package_root = create_package_tree(temp_dir / "src")
(package_root / "gamecontrollerdb.txt").unlink()
archive_path = temp_dir / "neser-linux-x86_64.tar.gz"
create_tar_gz(package_root, archive_path)
with self.assertRaisesRegex(
ReleasePackageVerificationError, "neser/gamecontrollerdb.txt"
):
verify_release_package(
VerificationConfig(
archive_path=archive_path,
binary_name="neser",
require_unix_executable=True,
)
)
def test_verify_package_reports_missing_system_readme(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)
package_root = create_package_tree(temp_dir / "src")
(package_root / "README-NES.md").unlink()
archive_path = temp_dir / "neser-linux-x86_64.tar.gz"
create_tar_gz(package_root, archive_path)
with self.assertRaisesRegex(
ReleasePackageVerificationError, "neser/README-NES.md"
):
verify_release_package(
VerificationConfig(
archive_path=archive_path,
binary_name="neser",
)
)
def test_verify_package_requires_default_shader_source(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)
package_root = create_package_tree(temp_dir / "src")
(package_root / "shaders/stock.slang").unlink()
archive_path = temp_dir / "neser-linux-x86_64.tar.gz"
create_tar_gz(package_root, archive_path)
with self.assertRaisesRegex(
ReleasePackageVerificationError, "neser/shaders/stock.slang"
):
verify_release_package(
VerificationConfig(
archive_path=archive_path,
binary_name="neser",
)
)
def test_verify_tar_gz_package_rejects_link_members(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)
package_root = create_package_tree(temp_dir / "src")
archive_path = temp_dir / "neser-linux-x86_64.tar.gz"
with tarfile.open(archive_path, "w:gz") as archive:
archive.add(package_root, arcname="neser")
link_info = tarfile.TarInfo("neser/shaders/escape")
link_info.type = tarfile.SYMTYPE
link_info.linkname = "../../outside"
archive.addfile(link_info)
with self.assertRaisesRegex(
ReleasePackageVerificationError, "unsupported tar link"
):
verify_release_package(
VerificationConfig(
archive_path=archive_path,
binary_name="neser",
)
)
def test_verify_package_reports_unsupported_single_suffix_archive(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
archive_path = Path(temp_dir_str) / "neser-linux-x86_64.tgz"
archive_path.write_bytes(b"not an archive")
with self.assertRaisesRegex(
ReleasePackageVerificationError, "unsupported archive format"
):
verify_release_package(
VerificationConfig(
archive_path=archive_path,
binary_name="neser",
)
)
def test_main_verifies_archive_from_cli_arguments(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)
package_root = create_package_tree(temp_dir / "src")
archive_path = temp_dir / "neser-linux-x86_64.tar.gz"
create_tar_gz(package_root, archive_path)
exit_code = main(
[
str(archive_path),
"--binary-name",
"neser",
"--require-unix-executable",
"--smoke-command",
"./neser",
"--version",
]
)
self.assertEqual(exit_code, 0)
def test_smoke_command_resolves_cwd_relative_executable_before_running(
self,
) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
package_root = Path(temp_dir_str) / "neser"
package_root.mkdir()
executable_path = package_root / "neser.exe"
with patch("scripts.verify_release_package.subprocess.run") as run:
run.return_value.returncode = 0
_run_smoke_command(["./neser.exe", "--version"], package_root)
run.assert_called_once()
command = run.call_args.args[0]
self.assertEqual(command[0], str(executable_path))
self.assertEqual(command[1:], ["--version"])
def test_smoke_command_resolves_windows_style_subdirectory_executable(
self,
) -> None:
with tempfile.TemporaryDirectory() as temp_dir_str:
package_root = Path(temp_dir_str) / "neser"
executable_path = package_root / "bin" / "neser.exe"
with patch("scripts.verify_release_package.subprocess.run") as run:
run.return_value.returncode = 0
_run_smoke_command([".\\bin\\neser.exe", "--version"], package_root)
run.assert_called_once()
command = run.call_args.args[0]
self.assertEqual(command[0], str(executable_path))
self.assertEqual(command[1:], ["--version"])
if __name__ == "__main__":
unittest.main()