Fix invocations of ideviceinstaller not passing DYLD_LIBRARY_PATH (#36327)
* add failing tests
* fix tests
* be more specific with try-catch
* add further mocking to get tests to pass again
* fix analyzer failure
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index 33e520d..4ed40de 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -191,15 +191,18 @@
@override
Future<bool> isAppInstalled(ApplicationPackage app) async {
+ RunResult apps;
try {
- final RunResult apps = await runCheckedAsync(<String>[_installerPath, '--list-apps']);
- if (RegExp(app.id, multiLine: true).hasMatch(apps.stdout)) {
- return true;
- }
- } catch (e) {
+ apps = await runCheckedAsync(
+ <String>[_installerPath, '--list-apps'],
+ environment: Map<String, String>.fromEntries(
+ <MapEntry<String, String>>[cache.dyLdLibEntry],
+ ),
+ );
+ } on ProcessException {
return false;
}
- return false;
+ return RegExp(app.id, multiLine: true).hasMatch(apps.stdout);
}
@override
@@ -215,9 +218,14 @@
}
try {
- await runCheckedAsync(<String>[_installerPath, '-i', iosApp.deviceBundlePath]);
+ await runCheckedAsync(
+ <String>[_installerPath, '-i', iosApp.deviceBundlePath],
+ environment: Map<String, String>.fromEntries(
+ <MapEntry<String, String>>[cache.dyLdLibEntry],
+ ),
+ );
return true;
- } catch (e) {
+ } on ProcessException {
return false;
}
}
@@ -225,9 +233,14 @@
@override
Future<bool> uninstallApp(ApplicationPackage app) async {
try {
- await runCheckedAsync(<String>[_installerPath, '-U', app.id]);
+ await runCheckedAsync(
+ <String>[_installerPath, '-U', app.id],
+ environment: Map<String, String>.fromEntries(
+ <MapEntry<String, String>>[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 0716212..f01894e 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 '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/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 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<String, String> libraryEntry = MapEntry<String, String>(
+ 'DYLD_LIBRARY_PATH',
+ '/path/to/libraries'
+ );
+ final Map<String, String> env = Map<String, String>.fromEntries(
+ <MapEntry<String, String>>[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<String> args = <String>[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<ProcessResult>.value(ProcessResult(1, 0, '', ''))
+ );
+ await device.installApp(mockApp);
+ verify(mockProcessManager.run(args, environment: env));
+ }, overrides: <Type, Generator>{
+ 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<String> args = <String>[installerPath, '--list-apps'];
+ when(mockProcessManager.run(args, environment: env))
+ .thenAnswer(
+ (_) => Future<ProcessResult>.value(ProcessResult(1, 0, '', ''))
+ );
+ when(mockApp.id).thenReturn(appId);
+ await device.isAppInstalled(mockApp);
+ verify(mockProcessManager.run(args, environment: env));
+ }, overrides: <Type, Generator>{
+ Artifacts: () => mockArtifacts,
+ Cache: () => mockCache,
+ Platform: () => macPlatform,
+ ProcessManager: () => mockProcessManager,
+ });
+
+ testUsingContext('uninstallApp() invokes process with correct environment', () async {
+ final IOSDevice device = IOSDevice('123');
+ final List<String> args = <String>[installerPath, '-U', appId];
+ when(mockApp.id).thenReturn(appId);
+ when(mockProcessManager.run(args, environment: env))
+ .thenAnswer(
+ (_) => Future<ProcessResult>.value(ProcessResult(1, 0, '', ''))
+ );
+ await device.uninstallApp(mockApp);
+ verify(mockProcessManager.run(args, environment: env));
+ }, overrides: <Type, Generator>{
+ Artifacts: () => mockArtifacts,
+ Cache: () => mockCache,
+ Platform: () => macPlatform,
+ ProcessManager: () => mockProcessManager,
+ });
+ });
group('getAttachedDevices', () {
MockIMobileDevice mockIMobileDevice;