Have runAsyncChecked throw a ProcessException instead of a String. (#22710)
diff --git a/packages/flutter_tools/lib/src/base/process.dart b/packages/flutter_tools/lib/src/base/process.dart index c612e45..5632752 100644 --- a/packages/flutter_tools/lib/src/base/process.dart +++ b/packages/flutter_tools/lib/src/base/process.dart
@@ -247,8 +247,10 @@ allowReentrantFlutter: allowReentrantFlutter, environment: environment, ); - if (result.exitCode != 0) - throw 'Exit code ${result.exitCode} from: ${cmd.join(' ')}:\n$result'; + if (result.exitCode != 0) { + throw ProcessException(cmd[0], cmd.sublist(1), + 'Process "${cmd[0]}" exited abnormally:\n$result', result.exitCode); + } return result; }
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index 587d6c6..207e822 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -120,22 +120,44 @@ } Future<RunResult> install(String deviceId, String appPath) { - return runCheckedAsync(<String>[_xcrunPath, 'simctl', 'install', deviceId, appPath]); + Future<RunResult> result; + try { + result = runCheckedAsync(<String>[_xcrunPath, 'simctl', 'install', deviceId, appPath]); + } on ProcessException catch (exception) { + throwToolExit('Unable to install $appPath on $deviceId:\n$exception'); + } + return result; } Future<RunResult> uninstall(String deviceId, String appId) { - return runCheckedAsync(<String>[_xcrunPath, 'simctl', 'uninstall', deviceId, appId]); + Future<RunResult> result; + try { + result = runCheckedAsync(<String>[_xcrunPath, 'simctl', 'uninstall', deviceId, appId]); + } on ProcessException catch (exception) { + throwToolExit('Unable to uninstall $appId from $deviceId:\n$exception'); + } + return result; } Future<RunResult> launch(String deviceId, String appIdentifier, [List<String> launchArgs]) { final List<String> args = <String>[_xcrunPath, 'simctl', 'launch', deviceId, appIdentifier]; if (launchArgs != null) args.addAll(launchArgs); - return runCheckedAsync(args); + Future<RunResult> result; + try { + result = runCheckedAsync(args); + } on ProcessException catch (exception) { + throwToolExit('Unable to launch $appIdentifier on $deviceId:\n$exception'); + } + return result; } Future<void> takeScreenshot(String deviceId, String outputPath) async { - await runCheckedAsync(<String>[_xcrunPath, 'simctl', 'io', deviceId, 'screenshot', outputPath]); + try { + await runCheckedAsync(<String>[_xcrunPath, 'simctl', 'io', deviceId, 'screenshot', outputPath]); + } on ProcessException catch (exception) { + throwToolExit('Unable to take screenshot of $deviceId:\n$exception'); + } } }
diff --git a/packages/flutter_tools/test/base/process_test.dart b/packages/flutter_tools/test/base/process_test.dart index 5f4aa4d..1281a92 100644 --- a/packages/flutter_tools/test/base/process_test.dart +++ b/packages/flutter_tools/test/base/process_test.dart
@@ -2,12 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/process.dart'; +import 'package:mockito/mockito.dart'; +import 'package:process/process.dart'; import '../src/common.dart'; import '../src/context.dart'; void main() { + group('process exceptions', () { + ProcessManager mockProcessManager; + + setUp(() { + mockProcessManager = MockProcessManager(); + }); + + testUsingContext('runCheckedAsync exceptions should be ProcessException objects', () async { + when(mockProcessManager.run(<String>['false'])) + .thenAnswer((Invocation invocation) => Future<ProcessResult>.value(ProcessResult(0, 1, '', ''))); + expect(() async => await runCheckedAsync(<String>['false']), throwsA(isInstanceOf<ProcessException>())); + }, overrides: <Type, Generator>{ProcessManager: () => mockProcessManager}); + }); group('shutdownHooks', () { testUsingContext('runInExpectedOrder', () async { int i = 1; @@ -41,3 +57,5 @@ }); }); } + +class MockProcessManager extends Mock implements ProcessManager {}