Files
escape-from-funcraft-client/tests/test_beta_release.py
T
2026-07-18 19:58:41 +05:00

173 lines
6.4 KiB
Python

import hashlib
from pathlib import Path
import pytest
from tools.beta_release_lib import validate_complete_mapping
def test_manifest_rejects_an_unclassified_or_missing_mod() -> None:
with pytest.raises(ValueError, match="missing=.*alpha.jar.*unknown=.*beta.jar"):
validate_complete_mapping(
{"alpha.jar", "beta.jar"},
{"beta.jar": "UNCLASSIFIED"},
)
def test_manifest_accepts_only_known_sides_and_exact_names() -> None:
validate_complete_mapping(
{"alpha.jar", "beta.jar"},
{"alpha.jar": "client", "beta.jar": "server"},
)
with pytest.raises(ValueError, match="extra=.*gamma.jar"):
validate_complete_mapping(
{"alpha.jar"}, {"alpha.jar": "both", "gamma.jar": "client"},
)
def test_write_keybind_options_keeps_only_version_and_key_lines(tmp_path: Path) -> None:
from tools.beta_release_lib import write_keybind_options
source = tmp_path / "source-options.txt"
destination = tmp_path / "options.txt"
source.write_text(
"version:3465\nrenderDistance:32\nkey_key.tacz.reload.desc:key.keyboard.r\n"
"fov:0.0\nkey_key.forward:key.keyboard.w\n",
encoding="utf-8",
)
write_keybind_options(source, destination)
assert destination.read_text(encoding="utf-8") == (
"version:3465\nkey_key.tacz.reload.desc:key.keyboard.r\nkey_key.forward:key.keyboard.w\n"
)
def test_copy_classified_tree_never_copies_wrong_side_or_world(tmp_path: Path) -> None:
from tools.beta_release_lib import copy_classified_tree
source = tmp_path / "source"
(source / "minecraft/mods").mkdir(parents=True)
(source / "minecraft/saves/world").mkdir(parents=True)
(source / "minecraft/mods/client.jar").write_bytes(b"client")
(source / "minecraft/mods/both.jar").write_bytes(b"both")
(source / "minecraft/mods/server.jar").write_bytes(b"server")
(source / "minecraft/saves/world/level.dat").write_bytes(b"world")
destination = tmp_path / "client"
copy_classified_tree(
source,
destination,
"client",
{"client.jar": "client", "both.jar": "both", "server.jar": "server"},
[],
)
assert (destination / "minecraft/mods/client.jar").is_file()
assert (destination / "minecraft/mods/both.jar").is_file()
assert not (destination / "minecraft/mods/server.jar").exists()
assert not (destination / "minecraft/saves").exists()
def test_validate_client_stage_requires_prism_root_and_rejects_world(tmp_path: Path) -> None:
from tools.beta_release_lib import validate_client_stage
stage = tmp_path / "client-stage"
(stage / "minecraft/saves/world").mkdir(parents=True)
(stage / "minecraft/saves/world/level.dat").write_bytes(b"world")
(stage / "minecraft/mods").mkdir()
(stage / "minecraft/options.txt").write_text("version:3465\n", encoding="utf-8")
(stage / "instance.cfg").write_text("InstanceType=OneSix\n", encoding="utf-8")
(stage / "mmc-pack.json").write_text("{}\n", encoding="utf-8")
with pytest.raises(ValueError, match="forbidden client path.*minecraft/saves"):
validate_client_stage(stage, {})
def test_sanitize_client_stage_removes_server_credentials_and_personal_cache(
tmp_path: Path,
) -> None:
from tools.beta_release_lib import sanitize_client_stage
stage = tmp_path / "client-stage"
credentials = stage / "minecraft/config/Discord-Integration.toml"
cache = stage / "minecraft/config/voicechat/username-cache.json"
shader_selection = stage / "minecraft/config/oculus.properties"
skin_provider = stage / "minecraft/config/skinrestorer/config.json"
credentials.parent.mkdir(parents=True)
cache.parent.mkdir(parents=True)
skin_provider.parent.mkdir(parents=True)
credentials.write_text("botToken=do-not-publish\n", encoding="utf-8")
cache.write_text('{"player":"do-not-publish"}\n', encoding="utf-8")
shader_selection.write_text("shaderPack=local-only\n", encoding="utf-8")
skin_provider.write_text('{"apiKey":"do-not-publish"}\n', encoding="utf-8")
sanitize_client_stage(stage)
assert not credentials.exists()
assert not cache.exists()
assert not shader_selection.exists()
assert not skin_provider.exists()
def test_validate_server_stage_rejects_client_jar_and_requires_target_world(tmp_path: Path) -> None:
from tools.beta_release_lib import validate_server_stage
stage = tmp_path / "server-stage"
(stage / "mods").mkdir(parents=True)
(stage / "mods/client.jar").write_bytes(b"client")
(stage / "eula.txt").write_text("eula=false\n", encoding="utf-8")
(stage / "server.properties").write_text("level-name=world\n", encoding="utf-8")
with pytest.raises(ValueError, match="server JAR mismatch|missing target world"):
validate_server_stage(stage, {"client.jar": "client"}, "world")
def test_forge_request_declares_a_user_agent() -> None:
from tools.build_beta_release import forge_request
request = forge_request("https://example.invalid/forge-installer.jar")
assert request.get_header("User-agent") == "EscapeFromFuncraftBetaBuilder/1.0"
def test_forge_install_env_prepends_compatibility_library_path(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
from tools.build_beta_release import forge_install_env
monkeypatch.setenv("LD_LIBRARY_PATH", "/system/lib")
env = forge_install_env(tmp_path / "legacy-zlib")
assert env is not None
assert env["LD_LIBRARY_PATH"] == f"{tmp_path / 'legacy-zlib'}:/system/lib"
def test_sha256_file_streams_without_reading_the_archive_at_once(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
from tools.beta_release_lib import sha256_file
archive = tmp_path / "large-archive.bin"
payload = b"release-data" * 100_000
archive.write_bytes(payload)
def fail_read_bytes(_: Path) -> bytes:
raise AssertionError("release archives must not be read into memory at once")
monkeypatch.setattr(Path, "read_bytes", fail_read_bytes)
assert sha256_file(archive) == hashlib.sha256(payload).hexdigest()
def test_source_mod_names_includes_only_mod_jars(tmp_path: Path) -> None:
from tools.build_beta_release import source_mod_names
mods = tmp_path / "minecraft/mods"
mods.mkdir(parents=True)
(mods / "required.jar").write_bytes(b"jar")
(mods / "notes.txt").write_text("ignore", encoding="utf-8")
assert source_mod_names(tmp_path) == {"required.jar"}