|
31 | 31 |
|
32 | 32 | from . import TestCase |
33 | 33 | import bitmath |
| 34 | +import ctypes as real_ctypes |
34 | 35 | import os |
| 36 | +import types |
35 | 37 | from unittest import mock, skipUnless |
36 | 38 | import struct |
37 | 39 | from contextlib import ExitStack, contextmanager |
@@ -133,3 +135,63 @@ def test_query_device_capacity_unsupported_platform_fails(self): |
133 | 135 | with mock.patch('bitmath.os.name', unsupported): |
134 | 136 | with self.assertRaises(NotImplementedError): |
135 | 137 | bitmath.query_device_capacity(device) |
| 138 | + |
| 139 | + |
| 140 | +class TestQueryDeviceCapacityWindowsBody(TestCase): |
| 141 | + """Mock-based tests for _query_device_capacity_windows body. |
| 142 | +
|
| 143 | + Run on all platforms by injecting ctypes and msvcrt into the bitmath |
| 144 | + namespace via mock.patch(..., create=True). |
| 145 | + """ |
| 146 | + |
| 147 | + def _make_mock_ctypes(self): |
| 148 | + mc = types.SimpleNamespace( |
| 149 | + Structure=real_ctypes.Structure, |
| 150 | + c_longlong=real_ctypes.c_longlong, |
| 151 | + c_uint=real_ctypes.c_uint, |
| 152 | + c_ulong=real_ctypes.c_ulong, |
| 153 | + c_byte=real_ctypes.c_byte, |
| 154 | + byref=real_ctypes.byref, |
| 155 | + sizeof=real_ctypes.sizeof, |
| 156 | + wintypes=types.SimpleNamespace(DWORD=real_ctypes.c_ulong), |
| 157 | + windll=mock.MagicMock(), |
| 158 | + ) |
| 159 | + mc.windll.kernel32.DeviceIoControl.return_value = 1 |
| 160 | + return mc |
| 161 | + |
| 162 | + def _make_mock_msvcrt(self): |
| 163 | + return types.SimpleNamespace(get_osfhandle=mock.Mock(return_value=999)) |
| 164 | + |
| 165 | + def _make_windows_device(self): |
| 166 | + fd = mock.MagicMock() |
| 167 | + fd.name = r'\\.\PhysicalDrive0' |
| 168 | + fd.fileno.return_value = 4 |
| 169 | + return fd |
| 170 | + |
| 171 | + def test_windows_body_success(self): |
| 172 | + """_query_device_capacity_windows succeeds via mocked ctypes and msvcrt""" |
| 173 | + mock_ctypes = self._make_mock_ctypes() |
| 174 | + mock_msvcrt = self._make_mock_msvcrt() |
| 175 | + device_fd = self._make_windows_device() |
| 176 | + |
| 177 | + with mock.patch('bitmath.ctypes', mock_ctypes, create=True): |
| 178 | + with mock.patch('bitmath.msvcrt', mock_msvcrt, create=True): |
| 179 | + result = bitmath._query_device_capacity_windows(device_fd) |
| 180 | + |
| 181 | + # DiskSize is 0 by default — mock DeviceIoControl does not fill the struct |
| 182 | + self.assertEqual(result, 0) |
| 183 | + mock_msvcrt.get_osfhandle.assert_called_once_with(4) |
| 184 | + mock_ctypes.windll.kernel32.DeviceIoControl.assert_called_once() |
| 185 | + |
| 186 | + def test_windows_body_ioctl_failure_raises_oserror(self): |
| 187 | + """_query_device_capacity_windows raises OSError when DeviceIoControl fails""" |
| 188 | + mock_ctypes = self._make_mock_ctypes() |
| 189 | + mock_ctypes.windll.kernel32.DeviceIoControl.return_value = 0 |
| 190 | + mock_ctypes.windll.kernel32.GetLastError.return_value = 5 |
| 191 | + mock_msvcrt = self._make_mock_msvcrt() |
| 192 | + device_fd = self._make_windows_device() |
| 193 | + |
| 194 | + with mock.patch('bitmath.ctypes', mock_ctypes, create=True): |
| 195 | + with mock.patch('bitmath.msvcrt', mock_msvcrt, create=True): |
| 196 | + with self.assertRaises(OSError): |
| 197 | + bitmath._query_device_capacity_windows(device_fd) |
0 commit comments