diff --git a/tests/mocks/windows_mock.py b/tests/mocks/windows_mock.py index 303b148..36c0a4a 100644 --- a/tests/mocks/windows_mock.py +++ b/tests/mocks/windows_mock.py @@ -1,5 +1,7 @@ import re from collections import namedtuple +from ctypes.wintypes import RECT, HMONITOR +from typing import Callable import win32con @@ -78,6 +80,24 @@ class dxva2: def DestroyPhysicalMonitor(handle): pass + @staticmethod + def GetNumberOfPhysicalMonitorsFromHMONITOR(monitor: HMONITOR, count_out): + for fake in FAKE_DISPLAYS: + if fake['laptop']: + continue + if fake['uid'].strip('0') != str(monitor.value): + continue + count_out._obj.value = 1 + break + else: + count_out._obj.value = 0 + return 1 + + @staticmethod + def GetPhysicalMonitorsFromHMONITOR(monitor: HMONITOR, array_size, array_out): + array_out[0].handle = int(monitor.value) + return 1 + @staticmethod def GetVCPFeatureAndVCPFeatureReply( handle, code, code_type_out=None, current_value_out=None, max_value_out=None @@ -90,6 +110,15 @@ def GetVCPFeatureAndVCPFeatureReply( def SetVCPFeature(handle, code, value_in): return 1 + class user32: + @staticmethod + def EnumDisplayMonitors(_hdc, _rect, enum_proc: Callable, _data): + for fake in FAKE_DISPLAYS: + if fake['laptop']: + continue + enum_proc(int(fake['uid'].strip('0')), 0, RECT(0, 0, 0, 0), 0) + return 1 + def mock_wmi_init(): return FakeWMI() diff --git a/tests/test_windows.py b/tests/test_windows.py index f5920af..b446496 100644 --- a/tests/test_windows.py +++ b/tests/test_windows.py @@ -78,26 +78,12 @@ class TestVCP(BrightnessMethodTest): @pytest.fixture def patch_get_display_info(self, patch_global_get_display_info, mocker: MockerFixture, method): '''Mock everything needed to get `VCP.get_display_info` to run''' - - def mock_iter_physical_monitors(start=0): - displays = method.get_display_info() - for display in displays[start:]: - yield displays.index(display) - # call cleanup function for testing convenience - ctypes.windll.dxva2.DestroyPhysicalMonitor(0) - mocker.patch.object(ctypes, 'windll', FakeWinDLL, create=True) # also patch locally imported version mocker.patch.object(sbc.windows, 'windll', FakeWinDLL) sbc.windows.__cache__.enabled = False - return mocker.patch.object( - sbc.windows.VCP, 'iter_physical_monitors', - Mock(side_effect=mock_iter_physical_monitors, spec=True), - create=True - ) - @pytest.fixture def patch_get_brightness(self, mocker: MockerFixture, patch_get_display_info): pass @@ -115,10 +101,11 @@ class TestGetBrightness(BrightnessMethodTest.TestGetBrightness): def test_handles_are_cleaned_up(self, mocker: MockerFixture, method, display_kw): ''' DestroyPhysicalMonitor should be called ONCE for each monitor iterated over. - When using the `display` kwarg, only one monitor should be iterated over and therefore only one - handle should be destroyed + When using the `display` kwarg, we still have to iterate over those displays in + `iter_physical_monitors`, but we only yield from the `start` kw, meaning that + `n + 1` handles must be destroyed, where n is the target display index. ''' - num_displays = 1 if display_kw is not None else len(method.get_display_info()) + num_displays = display_kw + 1 if display_kw is not None else len(method.get_display_info()) spy = mocker.spy(ctypes.windll.dxva2, 'DestroyPhysicalMonitor') method.get_brightness(display=display_kw) assert spy.call_count == num_displays @@ -158,8 +145,13 @@ def test_without(self, mocker: MockerFixture, method, subtests): class TestSetBrightness(BrightnessMethodTest.TestSetBrightness): @pytest.mark.parametrize('display_kw', [None, 0, 1, 2]) def test_handles_are_cleaned_up(self, mocker: MockerFixture, method, display_kw): - '''See equivalent test in `TestGetBrightness`''' - num_displays = 1 if display_kw is not None else len(method.get_display_info()) + ''' + DestroyPhysicalMonitor should be called ONCE for each monitor iterated over. + When using the `display` kwarg, we still have to iterate over those displays in + `iter_physical_monitors`, but we only yield from the `start` kw, meaning that + `n + 1` handles must be destroyed, where n is the target display index. + ''' + num_displays = display_kw + 1 if display_kw is not None else len(method.get_display_info()) spy = mocker.spy(ctypes.windll.dxva2, 'DestroyPhysicalMonitor') method.set_brightness(100, display=display_kw) assert spy.call_count == num_displays