"""ADB Android 设备搜索服务测试。""" import subprocess import unittest from src.android_device_service import ( AndroidDeviceSearchError, AndroidDeviceService, ) def completed(command, stdout="", stderr="", returncode=0): """创建一条假的 ADB 命令结果。""" return subprocess.CompletedProcess(command, returncode, stdout, stderr) class AndroidDeviceServiceTest(unittest.TestCase): def test_parse_usb_wifi_and_unavailable_devices(self): output = """List of devices attached USB-001 device product:p model:Pixel_8 device:husky transport_id:1 192.168.0.173:5555 offline transport_id:2 USB-002 unauthorized usb:1-2 transport_id:3 """ devices = AndroidDeviceService.parse_devices(output) self.assertEqual(len(devices), 3) self.assertEqual(devices[0].connection_type, "USB") self.assertEqual(devices[0].model, "Pixel 8") self.assertEqual(devices[1].connection_type, "Wi-Fi") self.assertEqual(devices[1].status, "offline") self.assertEqual(devices[2].status, "unauthorized") def test_search_reads_version_only_for_connected_device(self): commands = [] def runner(command, _timeout): commands.append(list(command)) if command == ["adb", "devices", "-l"]: return completed( command, "List of devices attached\n" "USB-001 device model:Pixel_8 transport_id:1\n" "192.168.0.173:5555 offline transport_id:2\n", ) return completed(command, "14\n") devices = AndroidDeviceService(runner).search() self.assertEqual(devices[0].android_version, "14") self.assertEqual(devices[1].android_version, "—") self.assertEqual(len(commands), 2) self.assertIn("ro.build.version.release", commands[1]) def test_missing_model_is_read_from_device(self): def runner(command, _timeout): if command == ["adb", "devices", "-l"]: return completed( command, "List of devices attached\nUSB-001 device transport_id:1\n", ) if command[-1] == "ro.product.model": return completed(command, "Redmi K70\n") return completed(command, "15\n") device = AndroidDeviceService(runner).search()[0] self.assertEqual(device.model, "Redmi K70") self.assertEqual(device.android_version, "15") def test_property_failure_keeps_discovered_device(self): def runner(command, _timeout): if command == ["adb", "devices", "-l"]: return completed( command, "List of devices attached\nUSB-001 device model:Phone\n", ) return completed(command, stderr="device disconnected", returncode=1) device = AndroidDeviceService(runner).search()[0] self.assertEqual(device.serial, "USB-001") self.assertEqual(device.android_version, "—") def test_missing_adb_has_recovery_message(self): def runner(_command, _timeout): raise FileNotFoundError("adb") with self.assertRaisesRegex(AndroidDeviceSearchError, "未找到 adb"): AndroidDeviceService(runner).search() def test_timeout_has_recovery_message(self): def runner(command, timeout): raise subprocess.TimeoutExpired(command, timeout) with self.assertRaisesRegex(AndroidDeviceSearchError, "搜索设备超时"): AndroidDeviceService(runner).search() def test_nonzero_exit_includes_adb_error(self): def runner(command, _timeout): return completed(command, stderr="ADB server didn't ACK", returncode=1) with self.assertRaisesRegex(AndroidDeviceSearchError, "didn't ACK"): AndroidDeviceService(runner).search() if __name__ == "__main__": unittest.main()