release v2.2
This commit was merged in pull request #8.
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user