| // Copyright 2020 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:convert'; |
| import 'dart:io'; |
| |
| import 'package:file/src/backends/memory/memory_file_system.dart'; |
| import 'package:mockito/mockito.dart'; |
| import 'package:test/test.dart'; |
| |
| import 'package:device_doctor/src/device.dart'; |
| import 'package:device_doctor/src/health.dart'; |
| import 'package:device_doctor/src/ios_device.dart'; |
| import 'package:device_doctor/src/utils.dart'; |
| |
| import 'fake_ios_device.dart'; |
| import 'utils.dart'; |
| |
| void main() { |
| group('IosDeviceDiscovery', () { |
| late FakeIosDeviceDiscovery deviceDiscovery; |
| late MockProcessManager processManager; |
| Process process; |
| |
| setUp(() { |
| deviceDiscovery = FakeIosDeviceDiscovery(MemoryFileSystem().file('output')); |
| processManager = MockProcessManager(); |
| }); |
| |
| test('deviceDiscovery', () async { |
| deviceDiscovery.outputs = <dynamic>['']; |
| expect(await deviceDiscovery.discoverDevices(), isEmpty); |
| final StringBuffer sb = StringBuffer(); |
| sb.writeln('abcdefg'); |
| deviceDiscovery.outputs = <dynamic>[sb.toString()]; |
| final List<Device> devices = await deviceDiscovery.discoverDevices(); |
| expect(devices.length, equals(1)); |
| expect(devices[0].deviceId, equals('abcdefg')); |
| }); |
| |
| test('checkDevices without device', () async { |
| deviceDiscovery.outputs = <dynamic>['']; |
| final Map<String, List<HealthCheckResult>> results = await deviceDiscovery.checkDevices(); |
| await expectLater(results.keys.length, 0); |
| }); |
| |
| test('checkDevices with device', () async { |
| process = FakeProcess(0, out: <List<int>>[]); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| deviceDiscovery.outputs = <dynamic>['abcdefg']; |
| final Map<String, List<HealthCheckResult>> results = |
| await deviceDiscovery.checkDevices(processManager: processManager); |
| expect(results['ios-device-abcdefg'], isNotNull); |
| expect(results.keys.length, equals(1)); |
| expect(results.keys.toList()[0], 'ios-device-abcdefg'); |
| final List<HealthCheckResult> healthCheckResults = results['ios-device-abcdefg']!; |
| expect(healthCheckResults.length, 7); |
| expect(healthCheckResults[0].name, kDeviceAccessCheckKey); |
| expect(healthCheckResults[0].succeeded, true); |
| expect(healthCheckResults[1].name, kKeychainUnlockCheckKey); |
| expect(healthCheckResults[1].succeeded, true); |
| expect(healthCheckResults[2].name, kCertCheckKey); |
| expect(healthCheckResults[2].succeeded, false); |
| expect(healthCheckResults[3].name, kDevicePairCheckKey); |
| expect(healthCheckResults[3].succeeded, false); |
| expect(healthCheckResults[4].name, kUserAutoLoginCheckKey); |
| expect(healthCheckResults[4].succeeded, false); |
| expect(healthCheckResults[5].name, kDeviceProvisioningProfileCheckKey); |
| expect(healthCheckResults[5].succeeded, false); |
| expect(healthCheckResults[6].name, kBatteryLevelCheckKey); |
| expect(healthCheckResults[6].succeeded, false); |
| }); |
| }); |
| |
| group('IosDeviceDiscovery - health checks', () { |
| late IosDeviceDiscovery deviceDiscovery; |
| late MockProcessManager processManager; |
| Process process; |
| List<List<int>> output; |
| |
| setUp(() { |
| processManager = MockProcessManager(); |
| deviceDiscovery = IosDeviceDiscovery(MemoryFileSystem().file('output')); |
| }); |
| |
| test('Keychain unlock check - success', () async { |
| process = FakeProcess(0); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = |
| await deviceDiscovery.keychainUnlockCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, true); |
| }); |
| |
| test('Keychain unlock check - exception', () async { |
| process = FakeProcess(1); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = |
| await deviceDiscovery.keychainUnlockCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, false); |
| expect(healthCheckResult.name, kKeychainUnlockCheckKey); |
| expect(healthCheckResult.details, 'Executable ${kUnlockLoginKeychain} failed with exit code 1.'); |
| }); |
| |
| test('Cert check - success', () async { |
| final StringBuffer sb = StringBuffer(); |
| sb.writeln('1) abcdefg "Apple Development: Flutter Devicelab (hijklmn)"'); |
| sb.writeln('1 valid identities found'); |
| output = <List<int>>[utf8.encode(sb.toString())]; |
| process = FakeProcess(0, out: output); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = await deviceDiscovery.certCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, true); |
| }); |
| |
| test('Cert check - failure without target certificate', () async { |
| final StringBuffer sb = StringBuffer(); |
| sb.writeln('abcdefg'); |
| sb.writeln('hijklmn'); |
| output = <List<int>>[utf8.encode(sb.toString())]; |
| process = FakeProcess(0, out: output); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = await deviceDiscovery.certCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, false); |
| expect(healthCheckResult.name, kCertCheckKey); |
| expect(healthCheckResult.details, sb.toString().trim()); |
| }); |
| |
| test('Cert check - failure with multiple certificates', () async { |
| final StringBuffer sb = StringBuffer(); |
| sb.writeln('1) abcdefg "Apple Development: Flutter Devicelab (hijklmn)"'); |
| |
| sb.writeln('1) opqrst "uvwxyz"'); |
| sb.writeln('2 valid identities found'); |
| output = <List<int>>[utf8.encode(sb.toString())]; |
| process = FakeProcess(0, out: output); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = await deviceDiscovery.certCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, false); |
| expect(healthCheckResult.name, kCertCheckKey); |
| expect(healthCheckResult.details, sb.toString().trim()); |
| }); |
| |
| test('Cert check - failure with revoked certificates', () async { |
| final StringBuffer sb = StringBuffer(); |
| sb.writeln('1) abcdefg "Apple Development: Flutter Devicelab (hijklmn)" (CSSMERR_TP_CERT_REVOKED)'); |
| sb.writeln('1 valid identities found'); |
| output = <List<int>>[utf8.encode(sb.toString())]; |
| process = FakeProcess(0, out: output); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = await deviceDiscovery.certCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, false); |
| expect(healthCheckResult.name, kCertCheckKey); |
| expect(healthCheckResult.details, sb.toString().trim()); |
| }); |
| |
| test('Cert check - exception', () async { |
| process = FakeProcess(1); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = await deviceDiscovery.certCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, false); |
| expect(healthCheckResult.name, kCertCheckKey); |
| expect(healthCheckResult.details, 'Executable security failed with exit code 1.'); |
| }); |
| |
| test('Device pair check - success', () async { |
| final StringBuffer sb = StringBuffer(); |
| sb.writeln('SUCCESS: Validated pairing with device abcdefg-hijklmn'); |
| output = <List<int>>[utf8.encode(sb.toString())]; |
| process = FakeProcess(0, out: output); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = await deviceDiscovery.devicePairCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, true); |
| }); |
| |
| test('Device pair check - failure', () async { |
| final StringBuffer sb = StringBuffer(); |
| sb.writeln('abcdefg'); |
| output = <List<int>>[utf8.encode(sb.toString())]; |
| process = FakeProcess(0, out: output); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = await deviceDiscovery.devicePairCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, false); |
| expect(healthCheckResult.name, kDevicePairCheckKey); |
| expect(healthCheckResult.details, sb.toString().trim()); |
| }); |
| |
| test('Device pair check - exception', () async { |
| process = FakeProcess(1); |
| when(processManager.start(any, workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final HealthCheckResult healthCheckResult = await deviceDiscovery.devicePairCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, false); |
| expect(healthCheckResult.name, kDevicePairCheckKey); |
| expect(healthCheckResult.details, 'Executable idevicepair failed with exit code 1.'); |
| }); |
| |
| group('Device provisioning profile check', () { |
| Process lsProcess; |
| Process securityProcess; |
| List<List<int>> lsOutput; |
| List<List<int>> securityOutput; |
| test('success', () async { |
| const String fileName = 'abcdefg'; |
| lsOutput = <List<int>>[utf8.encode(fileName)]; |
| lsProcess = FakeProcess(0, out: lsOutput); |
| |
| const String deviceID = 'deviceId'; |
| const String profileContent = '''<array> |
| <string>test1</string> |
| <string>$deviceID</string> |
| <string>test2</string> |
| </array> |
| '''; |
| securityOutput = <List<int>>[utf8.encode(profileContent)]; |
| securityProcess = FakeProcess(0, out: securityOutput); |
| |
| final String? homeDir = Platform.environment['HOME']; |
| when( |
| processManager.start( |
| <Object>['ls', '$homeDir/Library/MobileDevice/Provisioning\ Profiles'], |
| workingDirectory: anyNamed('workingDirectory'), |
| ), |
| ).thenAnswer((_) => Future.value(lsProcess)); |
| when( |
| processManager.start( |
| <Object>['security', 'cms', '-D', '-i', '$homeDir/Library/MobileDevice/Provisioning\ Profiles/$fileName'], |
| workingDirectory: anyNamed('workingDirectory'), |
| ), |
| ).thenAnswer((_) => Future.value(securityProcess)); |
| |
| final HealthCheckResult healthCheckResult = |
| await deviceDiscovery.deviceProvisioningProfileCheck(deviceID, processManager: processManager); |
| expect(healthCheckResult.succeeded, true); |
| expect(healthCheckResult.name, kDeviceProvisioningProfileCheckKey); |
| }); |
| |
| test('deviceId does not exist', () async { |
| const String fileName = 'abcdefg'; |
| lsOutput = <List<int>>[utf8.encode(fileName)]; |
| lsProcess = FakeProcess(0, out: lsOutput); |
| |
| const String deviceID = 'deviceId'; |
| const String profileContent = '''<array> |
| <string>test1</string> |
| <string>test2</string> |
| </array> |
| '''; |
| securityOutput = <List<int>>[utf8.encode(profileContent)]; |
| securityProcess = FakeProcess(0, out: securityOutput); |
| |
| final String? homeDir = Platform.environment['HOME']; |
| when( |
| processManager.start( |
| <Object>['ls', '$homeDir/Library/MobileDevice/Provisioning\ Profiles'], |
| workingDirectory: anyNamed('workingDirectory'), |
| ), |
| ).thenAnswer((_) => Future.value(lsProcess)); |
| when( |
| processManager.start( |
| <Object>['security', 'cms', '-D', '-i', '$homeDir/Library/MobileDevice/Provisioning\ Profiles/$fileName'], |
| workingDirectory: anyNamed('workingDirectory'), |
| ), |
| ).thenAnswer((_) => Future.value(securityProcess)); |
| |
| final HealthCheckResult healthCheckResult = |
| await deviceDiscovery.deviceProvisioningProfileCheck(deviceID, processManager: processManager); |
| expect(healthCheckResult.succeeded, false); |
| expect(healthCheckResult.name, kDeviceProvisioningProfileCheckKey); |
| expect(healthCheckResult.details, 'device does not exist in the provisioning profile'); |
| }); |
| }); |
| |
| group('Device battery check', () { |
| Process process; |
| List<List<int>> output; |
| test('battery level is okay', () async { |
| const String batteryLevel = '100'; |
| output = <List<int>>[utf8.encode(batteryLevel)]; |
| process = FakeProcess(0, out: output); |
| |
| when( |
| processManager.start( |
| <Object>['ideviceinfo', '-q', 'com.apple.mobile.battery', '-k', 'BatteryCurrentCapacity'], |
| workingDirectory: anyNamed('workingDirectory'), |
| ), |
| ).thenAnswer((_) => Future.value(process)); |
| |
| final HealthCheckResult healthCheckResult = |
| await deviceDiscovery.batteryLevelCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, true); |
| expect(healthCheckResult.name, kBatteryLevelCheckKey); |
| }); |
| |
| test('battery level is below minLevel', () async { |
| const String batteryLevel = '10'; |
| output = <List<int>>[utf8.encode(batteryLevel)]; |
| process = FakeProcess(0, out: output); |
| |
| when( |
| processManager.start( |
| <Object>['ideviceinfo', '-q', 'com.apple.mobile.battery', '-k', 'BatteryCurrentCapacity'], |
| workingDirectory: anyNamed('workingDirectory'), |
| ), |
| ).thenAnswer((_) => Future.value(process)); |
| |
| final HealthCheckResult healthCheckResult = |
| await deviceDiscovery.batteryLevelCheck(processManager: processManager); |
| expect(healthCheckResult.succeeded, false); |
| expect(healthCheckResult.name, kBatteryLevelCheckKey); |
| expect(healthCheckResult.details, 'Battery level ($batteryLevel) is below 15'); |
| }); |
| }); |
| }); |
| |
| group('IosDevice recovery checks', () { |
| IosDevice device; |
| late MockProcessManager processManager; |
| Process process; |
| Process whichProcess; |
| String output; |
| String ideviceinstallerPath; |
| String idevicediagnosticsPath; |
| |
| setUp(() { |
| processManager = MockProcessManager(); |
| }); |
| test('device restart - success', () async { |
| idevicediagnosticsPath = '/abc/def/idevicediagnostics'; |
| whichProcess = FakeProcess(0, out: <List<int>>[utf8.encode(idevicediagnosticsPath)]); |
| when( |
| processManager.start(<String>['which', 'idevicediagnostics'], workingDirectory: anyNamed('workingDirectory')), |
| ).thenAnswer((_) => Future.value(whichProcess)); |
| process = FakeProcess(0); |
| device = IosDevice(deviceId: 'abc'); |
| when( |
| processManager |
| .start(<Object>[idevicediagnosticsPath, 'restart'], workingDirectory: anyNamed('workingDirectory')), |
| ).thenAnswer((_) => Future.value(process)); |
| final bool result = await device.restart_device(processManager: processManager); |
| expect(result, isTrue); |
| }); |
| |
| test('device restart - failure', () async { |
| idevicediagnosticsPath = '/abc/def/idevicediagnostics'; |
| whichProcess = FakeProcess(0, out: <List<int>>[utf8.encode(idevicediagnosticsPath)]); |
| when( |
| processManager.start(<String>['which', 'idevicediagnostics'], workingDirectory: anyNamed('workingDirectory')), |
| ).thenAnswer((_) => Future.value(whichProcess)); |
| process = FakeProcess(1); |
| device = IosDevice(deviceId: 'abc'); |
| when( |
| processManager |
| .start(<Object>[idevicediagnosticsPath, 'restart'], workingDirectory: anyNamed('workingDirectory')), |
| ).thenAnswer((_) => Future.value(process)); |
| final bool result = await device.restart_device(processManager: processManager); |
| expect(result, isFalse); |
| }); |
| |
| test('device restart - skip 32 bit phone', () async { |
| device = IosDevice(deviceId: '822ef7958bba573829d85eef4df6cbdd86593730'); |
| final bool result = await device.restart_device(processManager: processManager); |
| expect(result, isTrue); |
| }); |
| |
| test('list applications - failure', () async { |
| device = IosDevice(deviceId: '822ef7958bba573829d85eef4df6cbdd86593730'); |
| process = FakeProcess(1); |
| ideviceinstallerPath = '/abc/def/ideviceinstaller'; |
| whichProcess = FakeProcess(0, out: <List<int>>[utf8.encode(ideviceinstallerPath)]); |
| when(processManager.start(<String>['which', 'ideviceinstaller'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(whichProcess)); |
| when(processManager.start(<Object>[ideviceinstallerPath, '-l'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| |
| final bool result = await device.uninstall_applications(processManager: processManager); |
| expect(result, isFalse); |
| }); |
| |
| test('uninstall applications - no device is available', () async { |
| ideviceinstallerPath = '/abc/def/ideviceinstaller'; |
| device = IosDevice(deviceId: '822ef7958bba573829d85eef4df6cbdd86593730'); |
| output = '''No device found. |
| '''; |
| process = FakeProcess(0, out: <List<int>>[utf8.encode(output)]); |
| whichProcess = FakeProcess(0, out: <List<int>>[utf8.encode(ideviceinstallerPath)]); |
| when(processManager.start(<String>['which', 'ideviceinstaller'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(whichProcess)); |
| when(processManager.start(<Object>[ideviceinstallerPath, '-l'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| final bool result = await device.uninstall_applications(processManager: processManager); |
| expect(result, isTrue); |
| }); |
| |
| test('uninstall applications - no application exist', () async { |
| ideviceinstallerPath = '/abc/def/ideviceinstaller'; |
| device = IosDevice(deviceId: '822ef7958bba573829d85eef4df6cbdd86593730'); |
| output = '''CFBundleIdentifier, CFBundleVersion, CFBundleDisplayName |
| '''; |
| process = FakeProcess(0, out: <List<int>>[utf8.encode(output)]); |
| whichProcess = FakeProcess(0, out: <List<int>>[utf8.encode(ideviceinstallerPath)]); |
| when(processManager.start(<String>['which', 'ideviceinstaller'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(whichProcess)); |
| when(processManager.start(<Object>[ideviceinstallerPath, '-l'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| |
| final bool result = await device.uninstall_applications(processManager: processManager); |
| expect(result, isTrue); |
| }); |
| |
| test('uninstall applications - applications exist with exception', () async { |
| ideviceinstallerPath = '/abc/def/ideviceinstaller'; |
| device = IosDevice(deviceId: '822ef7958bba573829d85eef4df6cbdd86593730'); |
| whichProcess = FakeProcess(0, out: <List<int>>[utf8.encode(ideviceinstallerPath)]); |
| output = '''CFBundleIdentifier, CFBundleVersion, CFBundleDisplayName |
| abc, def, ghi |
| jkl, mno, pqr |
| '''; |
| process = FakeProcess(0, out: <List<int>>[utf8.encode(output)]); |
| Process process_uninstall = FakeProcess(1); |
| when(processManager.start(<String>['which', 'ideviceinstaller'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(whichProcess)); |
| when(processManager.start(<Object>[ideviceinstallerPath, '-l'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| when( |
| processManager |
| .start(<Object>[ideviceinstallerPath, '-U', 'abc'], workingDirectory: anyNamed('workingDirectory')), |
| ).thenAnswer((_) => Future.value(process_uninstall)); |
| when( |
| processManager |
| .start(<Object>[ideviceinstallerPath, '-U', 'jkl'], workingDirectory: anyNamed('workingDirectory')), |
| ).thenAnswer((_) => Future.value(process_uninstall)); |
| |
| output = '''CFBundleIdentifier, CFBundleVersion, CFBundleDisplayName |
| abc, def, ghi |
| jkl, mno, pqr |
| '''; |
| process = FakeProcess(0, out: <List<int>>[utf8.encode(output)]); |
| process_uninstall = FakeProcess(1); |
| |
| final bool result = await device.uninstall_applications(processManager: processManager); |
| expect(result, isFalse); |
| }); |
| |
| test('uninstall applications - applications exist', () async { |
| ideviceinstallerPath = '/abc/def/ideviceinstaller'; |
| device = IosDevice(deviceId: '822ef7958bba573829d85eef4df6cbdd86593730'); |
| whichProcess = FakeProcess(0, out: <List<int>>[utf8.encode(ideviceinstallerPath)]); |
| output = '''CFBundleIdentifier, CFBundleVersion, CFBundleDisplayName |
| abc, def, ghi |
| jkl, mno, pqr |
| '''; |
| process = FakeProcess(0, out: <List<int>>[utf8.encode(output)]); |
| final Process process_uninstall = FakeProcess(0); |
| when(processManager.start(<String>['which', 'ideviceinstaller'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(whichProcess)); |
| when(processManager.start(<Object>[ideviceinstallerPath, '-l'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(process)); |
| when( |
| processManager |
| .start(<Object>[ideviceinstallerPath, '-U', 'abc'], workingDirectory: anyNamed('workingDirectory')), |
| ).thenAnswer((_) => Future.value(process_uninstall)); |
| when( |
| processManager |
| .start(<Object>[ideviceinstallerPath, '-U', 'jkl'], workingDirectory: anyNamed('workingDirectory')), |
| ).thenAnswer((_) => Future.value(process_uninstall)); |
| |
| final bool result = await device.uninstall_applications(processManager: processManager); |
| expect(result, isTrue); |
| }); |
| }); |
| |
| group('deviceListOutput', () { |
| late IosDeviceDiscovery deviceDiscovery; |
| late MockProcessManager processManager; |
| Process processIdeviceID; |
| Process processWhichIdeviceID; |
| |
| setUp(() { |
| processManager = MockProcessManager(); |
| deviceDiscovery = IosDeviceDiscovery(MemoryFileSystem().file('output')); |
| }); |
| |
| test('success', () async { |
| processIdeviceID = FakeProcess(0, out: <List<int>>[utf8.encode('abc')]); |
| processWhichIdeviceID = FakeProcess(0, out: <List<int>>[utf8.encode('/test/idevice_id')]); |
| when(processManager.start(<String>['which', 'idevice_id'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(processWhichIdeviceID)); |
| when(processManager.start(<String>['/test/idevice_id', '-l'], workingDirectory: anyNamed('workingDirectory'))) |
| .thenAnswer((_) => Future.value(processIdeviceID)); |
| final String deviceId = await deviceDiscovery.deviceListOutput(processManager: processManager); |
| expect(deviceId, 'abc'); |
| }); |
| }); |
| } |