"""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()