Checks / tests (ubuntu-latest, 3.11) (push) Canceled after 0s
Checks / tests (ubuntu-latest, 3.14) (push) Canceled after 0s
Checks / tests (windows-latest, 3.11) (push) Canceled after 0s
Checks / tests (windows-latest, 3.14) (push) Canceled after 0s
Checks / package (push) Canceled after 0s
89 lines
3.3 KiB
Python
89 lines
3.3 KiB
Python
"""Model the named overloads exported by Python/WinRT, not C# overloads."""
|
|
|
|
import asyncio
|
|
import contextlib
|
|
import io
|
|
import sys
|
|
import types
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from controller.probe import SPP_UUID, check_channel, probe
|
|
|
|
|
|
class ProbeTests(unittest.TestCase):
|
|
def test_projected_overloads_and_resource_cleanup(self):
|
|
closed = []
|
|
selector = "paired Bluetooth selector"
|
|
service = types.SimpleNamespace(
|
|
service_id=types.SimpleNamespace(uuid=SPP_UUID),
|
|
connection_host_name=types.SimpleNamespace(raw_name="speaker-host"),
|
|
connection_service_name="1",
|
|
close=lambda: closed.append("service"),
|
|
)
|
|
|
|
async def get_services(cache_mode):
|
|
self.assertEqual(cache_mode, 1)
|
|
return types.SimpleNamespace(error=0, services=[service])
|
|
|
|
async def from_id(device_id):
|
|
self.assertEqual(device_id, "device-id")
|
|
return types.SimpleNamespace(
|
|
bluetooth_address=0x123456789ABC,
|
|
get_rfcomm_services_with_cache_mode_async=get_services,
|
|
close=lambda: closed.append("device"),
|
|
)
|
|
|
|
async def find_filtered(value):
|
|
self.assertEqual(value, selector)
|
|
return [types.SimpleNamespace(name="MX-T40", id="device-id")]
|
|
|
|
def wrong_overload(value):
|
|
# The installed projection treats this argument as DeviceClass.
|
|
raise TypeError("'str' object cannot be interpreted as an integer")
|
|
|
|
bluetooth = types.SimpleNamespace(
|
|
BluetoothCacheMode=types.SimpleNamespace(UNCACHED=1),
|
|
BluetoothDevice=types.SimpleNamespace(
|
|
get_device_selector_from_pairing_state=lambda paired: selector,
|
|
from_id_async=from_id,
|
|
),
|
|
)
|
|
enumeration = types.SimpleNamespace(
|
|
DeviceInformation=types.SimpleNamespace(
|
|
find_all_async=wrong_overload,
|
|
find_all_async_aqs_filter=find_filtered,
|
|
)
|
|
)
|
|
with (
|
|
patch.dict(
|
|
sys.modules,
|
|
{
|
|
"winrt.windows.devices.bluetooth": bluetooth,
|
|
"winrt.windows.devices.enumeration": enumeration,
|
|
},
|
|
),
|
|
contextlib.redirect_stdout(io.StringIO()) as output,
|
|
):
|
|
result = asyncio.run(probe("MX-T40"))
|
|
self.assertEqual(result, 0)
|
|
self.assertIn("SPP service found: True", output.getvalue())
|
|
self.assertEqual(closed, ["service", "device"])
|
|
|
|
def test_direct_channel_connects_without_sending(self):
|
|
from unittest.mock import MagicMock
|
|
|
|
stream = MagicMock()
|
|
with (
|
|
patch("controller.probe.socket.socket") as create,
|
|
patch("controller.probe.socket.AF_BLUETOOTH", 32, create=True),
|
|
patch("controller.probe.socket.BTPROTO_RFCOMM", 3, create=True),
|
|
):
|
|
create.return_value.__enter__.return_value = stream
|
|
check_channel("12:34:56:78:9A:BC", 1)
|
|
stream.connect.assert_called_once_with(("12:34:56:78:9A:BC", 1))
|
|
stream.settimeout.assert_called_once_with(10)
|
|
stream.send.assert_not_called()
|
|
stream.sendall.assert_not_called()
|
|
create.return_value.__exit__.assert_called_once()
|