diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 33e520decf..4ed40de81f 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -191,15 +191,18 @@ class IOSDevice extends Device { @override Future isAppInstalled(ApplicationPackage app) async { + RunResult apps; try { - final RunResult apps = await runCheckedAsync([_installerPath, '--list-apps']); - if (RegExp(app.id, multiLine: true).hasMatch(apps.stdout)) { - return true; - } - } catch (e) { + apps = await runCheckedAsync( + [_installerPath, '--list-apps'], + environment: Map.fromEntries( + >[cache.dyLdLibEntry], + ), + ); + } on ProcessException { return false; } - return false; + return RegExp(app.id, multiLine: true).hasMatch(apps.stdout); } @override @@ -215,9 +218,14 @@ class IOSDevice extends Device { } try { - await runCheckedAsync([_installerPath, '-i', iosApp.deviceBundlePath]); + await runCheckedAsync( + [_installerPath, '-i', iosApp.deviceBundlePath], + environment: Map.fromEntries( + >[cache.dyLdLibEntry], + ), + ); return true; - } catch (e) { + } on ProcessException { return false; } } @@ -225,9 +233,14 @@ class IOSDevice extends Device { @override Future uninstallApp(ApplicationPackage app) async { try { - await runCheckedAsync([_installerPath, '-U', app.id]); + await runCheckedAsync( + [_installerPath, '-U', app.id], + environment: Map.fromEntries( + >[cache.dyLdLibEntry], + ), + ); return true; - } catch (e) { + } on ProcessException { return false; } } diff --git a/packages/flutter_tools/test/general.shard/ios/devices_test.dart b/packages/flutter_tools/test/general.shard/ios/devices_test.dart index 0716212deb..f01894e6e0 100644 --- a/packages/flutter_tools/test/general.shard/ios/devices_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/devices_test.dart @@ -7,8 +7,10 @@ import 'dart:async'; import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/application_package.dart'; +import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; +import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/ios/mac.dart'; @@ -22,6 +24,11 @@ import '../../src/common.dart'; import '../../src/context.dart'; import '../../src/mocks.dart'; +class MockIOSApp extends Mock implements IOSApp {} +class MockArtifacts extends Mock implements Artifacts {} +class MockCache extends Mock implements Cache {} +class MockDirectory extends Mock implements Directory {} +class MockFileSystem extends Mock implements FileSystem {} class MockIMobileDevice extends Mock implements IMobileDevice {} class MockProcessManager extends Mock implements ProcessManager {} class MockXcode extends Mock implements Xcode {} @@ -29,8 +36,96 @@ class MockFile extends Mock implements File {} class MockProcess extends Mock implements Process {} void main() { - final FakePlatform osx = FakePlatform.fromPlatform(const LocalPlatform()); - osx.operatingSystem = 'macos'; + final FakePlatform macPlatform = FakePlatform.fromPlatform(const LocalPlatform()); + macPlatform.operatingSystem = 'macos'; + + group('Process calls', () { + MockIOSApp mockApp; + MockArtifacts mockArtifacts; + MockCache mockCache; + MockFileSystem mockFileSystem; + MockProcessManager mockProcessManager; + const String installerPath = '/path/to/ideviceinstaller'; + const String appId = '789'; + const MapEntry libraryEntry = MapEntry( + 'DYLD_LIBRARY_PATH', + '/path/to/libraries' + ); + final Map env = Map.fromEntries( + >[libraryEntry] + ); + + setUp(() { + mockApp = MockIOSApp(); + mockArtifacts = MockArtifacts(); + mockCache = MockCache(); + when(mockCache.dyLdLibEntry).thenReturn(libraryEntry); + mockFileSystem = MockFileSystem(); + mockProcessManager = MockProcessManager(); + when( + mockArtifacts.getArtifactPath( + Artifact.ideviceinstaller, + platform: anyNamed('platform'), + ) + ).thenReturn(installerPath); + }); + + testUsingContext('installApp() invokes process with correct environment', () async { + final IOSDevice device = IOSDevice('123'); + const String bundlePath = '/path/to/bundle'; + final List args = [installerPath, '-i', bundlePath]; + when(mockApp.deviceBundlePath).thenReturn(bundlePath); + final MockDirectory directory = MockDirectory(); + when(mockFileSystem.directory(bundlePath)).thenReturn(directory); + when(directory.existsSync()).thenReturn(true); + when(mockProcessManager.run(args, environment: env)) + .thenAnswer( + (_) => Future.value(ProcessResult(1, 0, '', '')) + ); + await device.installApp(mockApp); + verify(mockProcessManager.run(args, environment: env)); + }, overrides: { + Artifacts: () => mockArtifacts, + Cache: () => mockCache, + FileSystem: () => mockFileSystem, + Platform: () => macPlatform, + ProcessManager: () => mockProcessManager, + }); + + testUsingContext('isAppInstalled() invokes process with correct environment', () async { + final IOSDevice device = IOSDevice('123'); + final List args = [installerPath, '--list-apps']; + when(mockProcessManager.run(args, environment: env)) + .thenAnswer( + (_) => Future.value(ProcessResult(1, 0, '', '')) + ); + when(mockApp.id).thenReturn(appId); + await device.isAppInstalled(mockApp); + verify(mockProcessManager.run(args, environment: env)); + }, overrides: { + Artifacts: () => mockArtifacts, + Cache: () => mockCache, + Platform: () => macPlatform, + ProcessManager: () => mockProcessManager, + }); + + testUsingContext('uninstallApp() invokes process with correct environment', () async { + final IOSDevice device = IOSDevice('123'); + final List args = [installerPath, '-U', appId]; + when(mockApp.id).thenReturn(appId); + when(mockProcessManager.run(args, environment: env)) + .thenAnswer( + (_) => Future.value(ProcessResult(1, 0, '', '')) + ); + await device.uninstallApp(mockApp); + verify(mockProcessManager.run(args, environment: env)); + }, overrides: { + Artifacts: () => mockArtifacts, + Cache: () => mockCache, + Platform: () => macPlatform, + ProcessManager: () => mockProcessManager, + }); + }); group('getAttachedDevices', () { MockIMobileDevice mockIMobileDevice;