Harden fixed Farclip ceiling and migration tests
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import stat
|
||||
import tkinter as tk
|
||||
from tkinter import messagebox, ttk
|
||||
|
||||
@@ -9,9 +7,6 @@ import dxvk_fps
|
||||
import setup_tool_dynamic
|
||||
|
||||
|
||||
_FARCLIP_EXE_FLOOR = 3000.0
|
||||
|
||||
|
||||
class ResponsiveModernWowSetupTool(setup_tool_dynamic.ModernWowSetupTool):
|
||||
"""Production entry point with display-scaling-safe UI and DXVK FPS control."""
|
||||
|
||||
@@ -247,83 +242,6 @@ class ResponsiveModernWowSetupTool(setup_tool_dynamic.ModernWowSetupTool):
|
||||
|
||||
return True
|
||||
|
||||
def _desired_normalized_values(self):
|
||||
desired = super()._desired_normalized_values()
|
||||
# The EXE field is a maximum allowed Farclip, not the active distance.
|
||||
# Keep a 3000 baseline ceiling so an existing Config.wtf value cannot
|
||||
# exceed a newly reduced executable limit. Values explicitly selected
|
||||
# above 3000 still raise the ceiling so the safety override keeps working.
|
||||
desired["farclip"] = max(_FARCLIP_EXE_FLOOR, desired["farclip"])
|
||||
return desired
|
||||
|
||||
def _configure_farclip_cvar(self, target):
|
||||
"""Apply the selected render distance to WTF/Config.wtf."""
|
||||
try:
|
||||
farclip = int(self.vt_farclip.get())
|
||||
except (tk.TclError, TypeError, ValueError) as exc:
|
||||
raise RuntimeError("Render Distance (Farclip) is not a valid number.") from exc
|
||||
if farclip <= 0:
|
||||
raise RuntimeError("Render Distance (Farclip) must be greater than 0.")
|
||||
|
||||
wtf_dir = os.path.join(target, "WTF")
|
||||
config_path = os.path.join(wtf_dir, "Config.wtf")
|
||||
staged = config_path + ".modernization-farclip"
|
||||
original_mode = None
|
||||
restore_readonly = False
|
||||
|
||||
try:
|
||||
os.makedirs(wtf_dir, exist_ok=True)
|
||||
|
||||
if os.path.exists(config_path):
|
||||
original_mode = os.stat(config_path).st_mode
|
||||
if not (original_mode & stat.S_IWRITE):
|
||||
os.chmod(config_path, original_mode | stat.S_IWRITE)
|
||||
restore_readonly = True
|
||||
|
||||
existing = ""
|
||||
if os.path.exists(config_path):
|
||||
with open(config_path, "r", encoding="utf-8", errors="ignore") as handle:
|
||||
existing = handle.read()
|
||||
|
||||
setting = f'SET farclip "{farclip}"'
|
||||
pattern = re.compile(
|
||||
r'^\s*SET\s+farclip\s+"[^"]*"\s*$',
|
||||
re.IGNORECASE | re.MULTILINE,
|
||||
)
|
||||
if pattern.search(existing):
|
||||
updated = pattern.sub(setting, existing)
|
||||
else:
|
||||
if existing and not existing.endswith(("\n", "\r")):
|
||||
existing += "\n"
|
||||
updated = existing + setting + "\n"
|
||||
|
||||
with open(staged, "w", encoding="utf-8", newline="") as handle:
|
||||
handle.write(updated)
|
||||
os.replace(staged, config_path)
|
||||
|
||||
except OSError as exc:
|
||||
raise RuntimeError(
|
||||
"Could not synchronize Render Distance in WTF\\Config.wtf. "
|
||||
"Close WoW and any program using the file, then try again."
|
||||
) from exc
|
||||
finally:
|
||||
if os.path.exists(staged):
|
||||
try:
|
||||
os.remove(staged)
|
||||
except OSError:
|
||||
pass
|
||||
if restore_readonly and original_mode is not None and os.path.exists(config_path):
|
||||
try:
|
||||
os.chmod(config_path, original_mode)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def configure_script_memory(self, target):
|
||||
# Keep the existing script-memory and SuperWoW FoV behavior, then make
|
||||
# the Tool's Render Distance selection authoritative at runtime too.
|
||||
super().configure_script_memory(target)
|
||||
self._configure_farclip_cvar(target)
|
||||
|
||||
def configure_dxvk(self, target):
|
||||
super().configure_dxvk(target)
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import unittest
|
||||
from unittest import mock
|
||||
|
||||
import setup_tool_dynamic
|
||||
import setup_tool_responsive
|
||||
|
||||
|
||||
class _Var:
|
||||
@@ -17,29 +16,46 @@ class _Var:
|
||||
|
||||
class FarclipConfigSyncTests(unittest.TestCase):
|
||||
def _tool(self, farclip=777):
|
||||
tool = object.__new__(setup_tool_responsive.ResponsiveModernWowSetupTool)
|
||||
tool = object.__new__(setup_tool_dynamic.ModernWowSetupTool)
|
||||
tool.vt_farclip = _Var(farclip)
|
||||
return tool
|
||||
|
||||
def test_executable_farclip_ceiling_has_3000_floor(self):
|
||||
tool = self._tool()
|
||||
with mock.patch.object(
|
||||
setup_tool_dynamic.ModernWowSetupTool,
|
||||
"_desired_normalized_values",
|
||||
return_value={"farclip": 777.0},
|
||||
):
|
||||
desired = tool._desired_normalized_values()
|
||||
@staticmethod
|
||||
def _add_numeric_vars(tool):
|
||||
tool.vt_fov = _Var(1.9199)
|
||||
tool.vt_frill = _Var(300)
|
||||
tool.vt_nameplate = _Var(41)
|
||||
tool.vt_maxcam = _Var(100)
|
||||
tool.vt_soundchan = _Var(64)
|
||||
|
||||
def test_executable_farclip_ceiling_is_always_3000(self):
|
||||
tool = self._tool(777)
|
||||
self._add_numeric_vars(tool)
|
||||
desired = tool._desired_normalized_values()
|
||||
self.assertEqual(desired["farclip"], 3000.0)
|
||||
|
||||
def test_executable_farclip_ceiling_keeps_explicit_value_above_3000(self):
|
||||
tool.vt_farclip = _Var(3000)
|
||||
desired = tool._desired_normalized_values()
|
||||
self.assertEqual(desired["farclip"], 3000.0)
|
||||
|
||||
def test_farclip_above_3000_is_rejected_even_with_direct_internal_call(self):
|
||||
tool = self._tool(5000)
|
||||
with mock.patch.object(
|
||||
setup_tool_dynamic.ModernWowSetupTool,
|
||||
"_desired_normalized_values",
|
||||
return_value={"farclip": 5000.0},
|
||||
):
|
||||
desired = tool._desired_normalized_values()
|
||||
self.assertEqual(desired["farclip"], 5000.0)
|
||||
self._add_numeric_vars(tool)
|
||||
with self.assertRaisesRegex(RuntimeError, "Farclip"):
|
||||
tool._desired_normalized_values()
|
||||
|
||||
def test_normalization_signature_bump_forces_existing_install_refresh(self):
|
||||
tool = self._tool(777)
|
||||
self._add_numeric_vars(tool)
|
||||
tool.vt_quickloot = _Var(True)
|
||||
tool.vt_bg_sound = _Var(True)
|
||||
tool.vt_laa = _Var(True)
|
||||
tool.vt_cam_fix = _Var(True)
|
||||
tool.vt_crossfaction_res = _Var(False)
|
||||
tool.vt_custom_glues = _Var(True)
|
||||
tool.vt_bluemoon = _Var(False)
|
||||
signature = tool._vanilla_tweaks_signature()
|
||||
self.assertEqual(signature["selected_patch_normalization"], 4)
|
||||
|
||||
def test_existing_farclip_cvar_is_replaced_without_touching_other_settings(self):
|
||||
tool = self._tool(777)
|
||||
@@ -88,10 +104,18 @@ class FarclipConfigSyncTests(unittest.TestCase):
|
||||
result = handle.read()
|
||||
self.assertEqual(result, 'SET farclip "1000"\n')
|
||||
|
||||
def test_farclip_cvar_rejects_value_above_fixed_ceiling(self):
|
||||
tool = self._tool(3001)
|
||||
with tempfile.TemporaryDirectory() as root:
|
||||
with self.assertRaisesRegex(RuntimeError, "3000"):
|
||||
tool._configure_farclip_cvar(root)
|
||||
self.assertFalse(os.path.exists(os.path.join(root, "WTF", "Config.wtf")))
|
||||
|
||||
def test_configure_script_memory_also_synchronizes_farclip(self):
|
||||
tool = self._tool(777)
|
||||
tool.core_plugins = {"SuperWoWhook.dll": _Var(False)}
|
||||
with mock.patch.object(
|
||||
setup_tool_dynamic.ModernWowSetupTool,
|
||||
setup_tool_dynamic._ModernWowSetupToolCore,
|
||||
"configure_script_memory",
|
||||
) as parent_configure, mock.patch.object(
|
||||
tool,
|
||||
|
||||
@@ -193,7 +193,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
self.assertEqual(result[0x3A4869], 0x14)
|
||||
self.assertEqual(result[0x126:0x128], b"\x0F\x01")
|
||||
self.assertAlmostEqual(self._read_float(result, 0x4089B4), 1.5708, places=4)
|
||||
self.assertEqual(self._read_float(result, 0x40FED8), 777.0)
|
||||
self.assertEqual(self._read_float(result, 0x40FED8), 3000.0)
|
||||
self.assertEqual(self._read_float(result, 0x467958), 70.0)
|
||||
self.assertEqual(self._read_float(result, 0x40C448), 20.0)
|
||||
self.assertEqual(self._read_float(result, 0x4089A4), 50.0)
|
||||
@@ -237,7 +237,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
self.assertEqual(result[0x3A4869], 0x27)
|
||||
self.assertEqual(result[0x126:0x128], b"\x2F\x01")
|
||||
self.assertAlmostEqual(self._read_float(result, 0x4089B4), 1.9199, places=4)
|
||||
self.assertEqual(self._read_float(result, 0x40FED8), 1500.0)
|
||||
self.assertEqual(self._read_float(result, 0x40FED8), 3000.0)
|
||||
self.assertEqual(self._read_float(result, 0x467958), 300.0)
|
||||
self.assertEqual(self._read_float(result, 0x40C448), 41.0)
|
||||
self.assertEqual(self._read_float(result, 0x4089A4), 100.0)
|
||||
@@ -581,7 +581,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
self.assertEqual(result[0x3A4869], 0x14)
|
||||
self.assertEqual(result[0x126:0x128], b"\x0F\x01")
|
||||
self.assertAlmostEqual(self._read_float(result, 0x4089B4), 1.5708, places=4)
|
||||
self.assertEqual(self._read_float(result, 0x40FED8), 777.0)
|
||||
self.assertEqual(self._read_float(result, 0x40FED8), 3000.0)
|
||||
self.assertEqual(self._read_float(result, 0x467958), 70.0)
|
||||
self.assertEqual(self._read_float(result, 0x40C448), 20.0)
|
||||
self.assertEqual(self._read_float(result, 0x4089A4), 50.0)
|
||||
@@ -627,7 +627,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
new_signature = tool._vanilla_tweaks_signature()
|
||||
|
||||
self.assertNotIn("selected_patch_normalization", old_signature)
|
||||
self.assertEqual(new_signature["selected_patch_normalization"], 3)
|
||||
self.assertEqual(new_signature["selected_patch_normalization"], 4)
|
||||
|
||||
tool.core_plugins["SuperWoWhook.dll"].set(False)
|
||||
self.assertEqual(new_signature, tool._vanilla_tweaks_signature())
|
||||
|
||||
Reference in New Issue
Block a user