diff --git a/tests/test_dxvk_fps_limit.py b/tests/test_dxvk_fps_limit.py index 4dc5856..5b864a3 100644 --- a/tests/test_dxvk_fps_limit.py +++ b/tests/test_dxvk_fps_limit.py @@ -1,5 +1,7 @@ +import ctypes import os import tempfile +import types import unittest from unittest import mock @@ -30,6 +32,41 @@ class DxvkFpsLimitTests(unittest.TestCase): with open(path, "r", encoding="utf-8") as handle: return handle.read() + def detect_with_fake_displays(self, devices, default=77): + """Run Windows display detection against deterministic fake Win32 APIs.""" + # Each record is (device name, state flags, refresh rate, settings_ok). + def enum_display_devices(_device, index, device_ptr, _flags): + if index >= len(devices): + return False + name, state_flags, _rate, _settings_ok = devices[index] + device_ptr._obj.DeviceName = name + device_ptr._obj.StateFlags = state_flags + return True + + def enum_display_settings(device_name, _mode, mode_ptr): + for name, _state_flags, rate, settings_ok in devices: + if name != device_name: + continue + if not settings_ok: + return False + mode_ptr._obj.dmDisplayFrequency = rate + return True + return False + + fake_user32 = types.SimpleNamespace( + EnumDisplayDevicesW=enum_display_devices, + EnumDisplaySettingsW=enum_display_settings, + ) + fake_windll = types.SimpleNamespace(user32=fake_user32) + + with mock.patch.object(dxvk_fps.os, "name", "nt"), mock.patch.object( + ctypes, + "windll", + fake_windll, + create=True, + ): + return dxvk_fps.detect_max_refresh_rate(default=default) + def test_enable_replaces_bundled_commented_value_and_preserves_other_options(self): with tempfile.TemporaryDirectory() as root: path = self.write_config( @@ -79,6 +116,24 @@ class DxvkFpsLimitTests(unittest.TestCase): self.assertIn("d3d9.maxFrameRate = 240\n", updated) self.assertIn("dxvk.allowFse = False\n", updated) + def test_signed_legacy_values_are_replaced_without_duplicates(self): + with tempfile.TemporaryDirectory() as root: + path = self.write_config( + root, + "d3d9.maxFrameRate = -120\n" + "# d3d9.maxFrameRate = +90\n" + "dxvk.allowFse = False\n", + ) + + dxvk_fps.apply_dxvk_fps_limit(path, True, 165) + updated = self.read_config(path) + + self.assertEqual(updated.count("d3d9.maxFrameRate"), 1) + self.assertIn("d3d9.maxFrameRate = 165\n", updated) + self.assertNotIn("-120", updated) + self.assertNotIn("+90", updated) + self.assertIn("dxvk.allowFse = False\n", updated) + def test_missing_limit_line_is_appended(self): with tempfile.TemporaryDirectory() as root: path = self.write_config(root, "dxvk.allowFse = False\n") @@ -99,6 +154,34 @@ class DxvkFpsLimitTests(unittest.TestCase): self.assertEqual(self.read_config(path), original) + def test_refresh_detection_uses_fastest_attached_valid_display(self): + detected = self.detect_with_fake_displays( + [ + ("DISPLAY1", 0x00000001, 60, True), + # Faster but not attached to the desktop: must be ignored. + ("DISPLAY2", 0x00000000, 360, True), + ("DISPLAY3", 0x00000001, 165, True), + # Windows unknown/default frequency: must be ignored. + ("DISPLAY4", 0x00000001, 1, True), + # Current settings query failed: must be ignored. + ("DISPLAY5", 0x00000001, 240, False), + ], + default=77, + ) + self.assertEqual(detected, 165) + + def test_refresh_detection_falls_back_when_no_usable_display_rate_exists(self): + detected = self.detect_with_fake_displays( + [ + ("DISPLAY1", 0x00000000, 240, True), + ("DISPLAY2", 0x00000001, 0, True), + ("DISPLAY3", 0x00000001, 1, True), + ("DISPLAY4", 0x00000001, 165, False), + ], + default=77, + ) + self.assertEqual(detected, 77) + def test_refresh_detection_always_returns_a_positive_integer(self): detected = dxvk_fps.detect_max_refresh_rate(default=77) self.assertIsInstance(detected, int)