Harden fixed Farclip ceiling and migration tests

This commit is contained in:
2026-09-06 21:03:45 +02:00
parent 0eb62fbf04
commit 0faf9ce25b
3 changed files with 47 additions and 105 deletions
-82
View File
@@ -1,7 +1,5 @@
import json import json
import os import os
import re
import stat
import tkinter as tk import tkinter as tk
from tkinter import messagebox, ttk from tkinter import messagebox, ttk
@@ -9,9 +7,6 @@ import dxvk_fps
import setup_tool_dynamic import setup_tool_dynamic
_FARCLIP_EXE_FLOOR = 3000.0
class ResponsiveModernWowSetupTool(setup_tool_dynamic.ModernWowSetupTool): class ResponsiveModernWowSetupTool(setup_tool_dynamic.ModernWowSetupTool):
"""Production entry point with display-scaling-safe UI and DXVK FPS control.""" """Production entry point with display-scaling-safe UI and DXVK FPS control."""
@@ -247,83 +242,6 @@ class ResponsiveModernWowSetupTool(setup_tool_dynamic.ModernWowSetupTool):
return True 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): def configure_dxvk(self, target):
super().configure_dxvk(target) super().configure_dxvk(target)
+43 -19
View File
@@ -4,7 +4,6 @@ import unittest
from unittest import mock from unittest import mock
import setup_tool_dynamic import setup_tool_dynamic
import setup_tool_responsive
class _Var: class _Var:
@@ -17,29 +16,46 @@ class _Var:
class FarclipConfigSyncTests(unittest.TestCase): class FarclipConfigSyncTests(unittest.TestCase):
def _tool(self, farclip=777): def _tool(self, farclip=777):
tool = object.__new__(setup_tool_responsive.ResponsiveModernWowSetupTool) tool = object.__new__(setup_tool_dynamic.ModernWowSetupTool)
tool.vt_farclip = _Var(farclip) tool.vt_farclip = _Var(farclip)
return tool return tool
def test_executable_farclip_ceiling_has_3000_floor(self): @staticmethod
tool = self._tool() def _add_numeric_vars(tool):
with mock.patch.object( tool.vt_fov = _Var(1.9199)
setup_tool_dynamic.ModernWowSetupTool, tool.vt_frill = _Var(300)
"_desired_normalized_values", tool.vt_nameplate = _Var(41)
return_value={"farclip": 777.0}, tool.vt_maxcam = _Var(100)
): tool.vt_soundchan = _Var(64)
desired = tool._desired_normalized_values()
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) 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) tool = self._tool(5000)
with mock.patch.object( self._add_numeric_vars(tool)
setup_tool_dynamic.ModernWowSetupTool, with self.assertRaisesRegex(RuntimeError, "Farclip"):
"_desired_normalized_values", tool._desired_normalized_values()
return_value={"farclip": 5000.0},
): def test_normalization_signature_bump_forces_existing_install_refresh(self):
desired = tool._desired_normalized_values() tool = self._tool(777)
self.assertEqual(desired["farclip"], 5000.0) 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): def test_existing_farclip_cvar_is_replaced_without_touching_other_settings(self):
tool = self._tool(777) tool = self._tool(777)
@@ -88,10 +104,18 @@ class FarclipConfigSyncTests(unittest.TestCase):
result = handle.read() result = handle.read()
self.assertEqual(result, 'SET farclip "1000"\n') 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): def test_configure_script_memory_also_synchronizes_farclip(self):
tool = self._tool(777) tool = self._tool(777)
tool.core_plugins = {"SuperWoWhook.dll": _Var(False)}
with mock.patch.object( with mock.patch.object(
setup_tool_dynamic.ModernWowSetupTool, setup_tool_dynamic._ModernWowSetupToolCore,
"configure_script_memory", "configure_script_memory",
) as parent_configure, mock.patch.object( ) as parent_configure, mock.patch.object(
tool, tool,
+4 -4
View File
@@ -193,7 +193,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
self.assertEqual(result[0x3A4869], 0x14) self.assertEqual(result[0x3A4869], 0x14)
self.assertEqual(result[0x126:0x128], b"\x0F\x01") self.assertEqual(result[0x126:0x128], b"\x0F\x01")
self.assertAlmostEqual(self._read_float(result, 0x4089B4), 1.5708, places=4) 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, 0x467958), 70.0)
self.assertEqual(self._read_float(result, 0x40C448), 20.0) self.assertEqual(self._read_float(result, 0x40C448), 20.0)
self.assertEqual(self._read_float(result, 0x4089A4), 50.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[0x3A4869], 0x27)
self.assertEqual(result[0x126:0x128], b"\x2F\x01") self.assertEqual(result[0x126:0x128], b"\x2F\x01")
self.assertAlmostEqual(self._read_float(result, 0x4089B4), 1.9199, places=4) 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, 0x467958), 300.0)
self.assertEqual(self._read_float(result, 0x40C448), 41.0) self.assertEqual(self._read_float(result, 0x40C448), 41.0)
self.assertEqual(self._read_float(result, 0x4089A4), 100.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[0x3A4869], 0x14)
self.assertEqual(result[0x126:0x128], b"\x0F\x01") self.assertEqual(result[0x126:0x128], b"\x0F\x01")
self.assertAlmostEqual(self._read_float(result, 0x4089B4), 1.5708, places=4) 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, 0x467958), 70.0)
self.assertEqual(self._read_float(result, 0x40C448), 20.0) self.assertEqual(self._read_float(result, 0x40C448), 20.0)
self.assertEqual(self._read_float(result, 0x4089A4), 50.0) self.assertEqual(self._read_float(result, 0x4089A4), 50.0)
@@ -627,7 +627,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
new_signature = tool._vanilla_tweaks_signature() new_signature = tool._vanilla_tweaks_signature()
self.assertNotIn("selected_patch_normalization", old_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) tool.core_plugins["SuperWoWhook.dll"].set(False)
self.assertEqual(new_signature, tool._vanilla_tweaks_signature()) self.assertEqual(new_signature, tool._vanilla_tweaks_signature())