release v2.2

This commit was merged in pull request #8.
This commit is contained in:
Dusk-92
2026-09-03 16:42:37 +02:00
committed by GitHub
parent 098852175e
commit 9c397218a7
6 changed files with 544 additions and 154 deletions
+242
View File
@@ -1,3 +1,4 @@
import hashlib
import json
import os
import struct
@@ -645,6 +646,62 @@ class SmartUpdateTests(unittest.TestCase):
remote_packages._package_state_is_current(root, "example", "v1")
)
def test_current_package_cleans_stale_transaction_backup(self):
with tempfile.TemporaryDirectory() as root:
dll = os.path.join(root, "UnitXP_SP3.dll")
with open(dll, "wb") as handle:
handle.write(b"current-unitxp")
remote_packages._record_package_state(
root,
"unitxp_sp3",
"v90",
["UnitXP_SP3.dll"],
)
stale_backup = dll + ".modernization-backup-941614e28c62"
with open(stale_backup, "wb") as handle:
handle.write(b"old-unitxp")
self.assertTrue(
remote_packages._package_state_is_current(
root,
"unitxp_sp3",
"v90",
)
)
self.assertFalse(os.path.exists(stale_backup))
self.assertTrue(os.path.isfile(dll))
def test_non_current_package_keeps_transaction_backup_for_recovery(self):
with tempfile.TemporaryDirectory() as root:
dll = os.path.join(root, "UnitXP_SP3.dll")
with open(dll, "wb") as handle:
handle.write(b"current-unitxp")
remote_packages._record_package_state(
root,
"unitxp_sp3",
"v90",
["UnitXP_SP3.dll"],
)
stale_backup = dll + ".modernization-backup-recovery"
with open(stale_backup, "wb") as handle:
handle.write(b"old-unitxp")
with open(dll, "wb") as handle:
handle.write(b"modified-after-state")
self.assertFalse(
remote_packages._package_state_is_current(
root,
"unitxp_sp3",
"v90",
)
)
self.assertTrue(os.path.exists(stale_backup))
def test_release_asset_revision_detects_replaced_asset_under_same_tag(self):
release_a = {
"tag_name": "Release",
@@ -1172,5 +1229,190 @@ class SettingsRecoveryTests(unittest.TestCase):
self.assertEqual(handle.read(), damaged)
class BundledComponentSafetyTests(unittest.TestCase):
def test_bundled_integrity_uses_recorded_sha256_and_size(self):
tool = ModernWowSetupTool.__new__(ModernWowSetupTool)
with tempfile.TemporaryDirectory() as root:
payload = os.path.join(root, "Payload")
fallback = os.path.join(payload, "Fallback")
os.makedirs(fallback)
source = os.path.join(payload, "component.bin")
with open(source, "wb") as handle:
handle.write(b"known bundled component")
expected_sha = hashlib.sha256(
b"known bundled component"
).hexdigest()
with open(
os.path.join(fallback, "versions.json"),
"w",
encoding="utf-8",
) as handle:
json.dump(
{
"components": {
"test": {
"files": [
{
"path": "Payload/component.bin",
"size": os.path.getsize(source),
"sha256": expected_sha,
}
]
}
}
},
handle,
)
with mock.patch("setup_tool_dynamic.get_base_path", return_value=root):
verified, digest = tool._verified_bundled_file(
"Payload/component.bin",
"test component",
)
self.assertEqual(verified, source)
self.assertEqual(digest, expected_sha)
with open(source, "ab") as handle:
handle.write(b"!")
with self.assertRaises(RuntimeError):
tool._verified_bundled_file(
"Payload/component.bin",
"test component",
)
def test_copy_base_files_does_not_copy_component_addons(self):
tool = ModernWowSetupTool.__new__(ModernWowSetupTool)
tool.install_autologin = FakeVar(False)
with tempfile.TemporaryDirectory() as root:
payload = os.path.join(root, "Payload")
os.makedirs(os.path.join(payload, "Interface", "Addons", "nampowersettings"))
vanilla_fixes = os.path.join(payload, "VanillaFixes.exe")
vf_patcher = os.path.join(payload, "VfPatcher.dll")
for path in (vanilla_fixes, vf_patcher):
with open(path, "wb") as handle:
handle.write(b"test")
tool._verified_bundled_file = mock.Mock(
side_effect=[
(vanilla_fixes, "a" * 64),
(vf_patcher, "b" * 64),
]
)
target = os.path.join(root, "game")
os.makedirs(target)
with (
mock.patch("setup_tool_dynamic.get_base_path", return_value=root),
mock.patch.object(
remote_packages,
"_transactional_replace_bundle",
) as transaction,
):
tool.copy_base_files(target)
self.assertFalse(os.path.exists(os.path.join(target, "Interface")))
transaction.assert_called_once()
items = transaction.call_args.args[0]
self.assertEqual(
[os.path.basename(item[2]) for item in items],
["VanillaFixes.exe", "VfPatcher.dll"],
)
def test_no1600_uses_bundled_copy_without_online_update(self):
tool = ModernWowSetupTool.__new__(ModernWowSetupTool)
tool.rendering_mode = FakeVar("directx9")
tool.core_plugins = {}
tool.classicapi_enabled = FakeVar(False)
tool.auction_throttle_enabled = FakeVar(False)
tool.addon_dependencies = {}
tool.optional_plugins = {
"no1600x1200.dll": FakeVar(True),
}
tool.vmmfix_enabled = FakeVar(False)
tool.interact_enabled = FakeVar(False)
tool._install_verified_bundled_file = mock.Mock()
tool._write_dlls_file = mock.Mock()
tool._close_download_progress = mock.Mock()
tool._report_download_progress = mock.Mock()
with tempfile.TemporaryDirectory() as root:
with mock.patch.object(
remote_packages,
"install_no1600x1200",
) as online_installer:
tool.configure_plugins(root)
online_installer.assert_not_called()
tool._install_verified_bundled_file.assert_called_once_with(
"Payload/no1600x1200.dll",
mock.ANY,
"no1600x1200.dll",
)
self.assertEqual(
os.path.basename(
tool._install_verified_bundled_file.call_args.args[1]
),
"no1600x1200.dll",
)
def test_superapi_tracks_master_revision(self):
release = {
"name": "SuperWoW 2.2",
"tag_name": "Release",
"id": 1,
"assets": [
{
"name": "SuperWoW.zip",
"id": 2,
"updated_at": "2026-07-16T00:00:00Z",
"size": 123,
}
],
}
with (
mock.patch.object(remote_packages, "_latest_release", return_value=release),
mock.patch.object(
remote_packages,
"_package_state_is_current",
return_value=True,
) as state,
mock.patch.object(
remote_packages,
"_branch_head_sha",
return_value="abc1234",
) as branch_head,
):
remote_packages.install_superwow("C:/WoW")
branch_head.assert_called_once_with("balakethelock/SuperAPI", "master")
revision = state.call_args.args[2]
self.assertIn("superapi:abc1234", revision)
def test_branch_archive_download_can_be_pinned_to_resolved_revision(self):
with (
mock.patch.object(remote_packages, "_download", return_value="archive.zip") as download,
mock.patch.object(remote_packages, "_branch_head_sha") as branch_head,
):
result = remote_packages._download_github_branch_archive(
"owner/repo",
"main",
revision="abc1234",
)
self.assertEqual(result, "archive.zip")
branch_head.assert_not_called()
self.assertEqual(
download.call_args.args[0],
"https://codeload.github.com/owner/repo/zip/abc1234",
)
if __name__ == "__main__":
unittest.main()