mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
Launch named iOS simulators (#72323)
This commit is contained in:
parent
d2d0c73f89
commit
84a7a611b0
|
@ -142,7 +142,7 @@ class AndroidEmulator extends Emulator {
|
|||
Category get category => Category.mobile;
|
||||
|
||||
@override
|
||||
PlatformType get platformType => PlatformType.android;
|
||||
String get platformDisplay => PlatformType.android.toString();
|
||||
|
||||
String _prop(String name) => _properties != null ? _properties[name] : null;
|
||||
|
||||
|
|
|
@ -933,7 +933,7 @@ Map<String, dynamic> _emulatorToMap(Emulator emulator) {
|
|||
'id': emulator.id,
|
||||
'name': emulator.name,
|
||||
'category': emulator.category?.toString(),
|
||||
'platformType': emulator.platformType?.toString(),
|
||||
'platformType': emulator.platformDisplay,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class EmulatorsCommand extends FlutterCommand {
|
|||
final String description = 'List, launch and create emulators.';
|
||||
|
||||
@override
|
||||
final List<String> aliases = <String>['emulator'];
|
||||
final List<String> aliases = <String>['emulator', 'simulators', 'simulator'];
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
|
|
|
@ -614,10 +614,6 @@ abstract class Device {
|
|||
/// Check if the device is supported by Flutter.
|
||||
bool isSupported();
|
||||
|
||||
// String meant to be displayed to the user indicating if the device is
|
||||
// supported by Flutter, and, if not, why.
|
||||
String supportMessage() => isSupported() ? 'Supported' : 'Unsupported';
|
||||
|
||||
/// The device's platform.
|
||||
Future<TargetPlatform> get targetPlatform;
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ abstract class Emulator {
|
|||
String get name;
|
||||
String get manufacturer;
|
||||
Category get category;
|
||||
PlatformType get platformType;
|
||||
String get platformDisplay;
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
|
@ -283,7 +283,7 @@ abstract class Emulator {
|
|||
emulator.id ?? '',
|
||||
emulator.name ?? '',
|
||||
emulator.manufacturer ?? '',
|
||||
emulator.platformType?.toString() ?? '',
|
||||
emulator.platformDisplay ?? '',
|
||||
],
|
||||
];
|
||||
|
||||
|
|
|
@ -16,17 +16,26 @@ class IOSEmulators extends EmulatorDiscovery {
|
|||
bool get canListAnything => globals.iosWorkflow.canListEmulators;
|
||||
|
||||
@override
|
||||
Future<List<Emulator>> get emulators async => getEmulators();
|
||||
Future<List<Emulator>> get emulators async {
|
||||
final List<IOSSimulator> simulators = await globals.iosSimulatorUtils.getAvailableDevices();
|
||||
return simulators.map<Emulator>((IOSSimulator device) {
|
||||
return IOSEmulator(device);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
bool get canLaunchAnything => canListAnything;
|
||||
}
|
||||
|
||||
class IOSEmulator extends Emulator {
|
||||
const IOSEmulator(String id) : super(id, true);
|
||||
IOSEmulator(IOSSimulator simulator)
|
||||
: _simulator = simulator,
|
||||
super(simulator.id, true);
|
||||
|
||||
final IOSSimulator _simulator;
|
||||
|
||||
@override
|
||||
String get name => 'iOS Simulator';
|
||||
String get name => _simulator.name;
|
||||
|
||||
@override
|
||||
String get manufacturer => 'Apple';
|
||||
|
@ -35,43 +44,20 @@ class IOSEmulator extends Emulator {
|
|||
Category get category => Category.mobile;
|
||||
|
||||
@override
|
||||
PlatformType get platformType => PlatformType.ios;
|
||||
String get platformDisplay =>
|
||||
// com.apple.CoreSimulator.SimRuntime.iOS-10-3 => iOS-10-3
|
||||
_simulator.simulatorCategory?.split('.')?.last ?? 'ios';
|
||||
|
||||
@override
|
||||
Future<void> launch() async {
|
||||
Future<bool> launchSimulator(List<String> additionalArgs) async {
|
||||
final List<String> args = <String>[
|
||||
'open',
|
||||
...additionalArgs,
|
||||
'-a',
|
||||
globals.xcode.getSimulatorPath(),
|
||||
];
|
||||
|
||||
final RunResult launchResult = await globals.processUtils.run(args);
|
||||
if (launchResult.exitCode != 0) {
|
||||
globals.printError('$launchResult');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
final RunResult launchResult = await globals.processUtils.run(<String>[
|
||||
'open',
|
||||
'-a',
|
||||
globals.xcode.getSimulatorPath(),
|
||||
]);
|
||||
if (launchResult.exitCode != 0) {
|
||||
globals.printError('$launchResult');
|
||||
}
|
||||
|
||||
// First run with `-n` to force a device to boot if there isn't already one
|
||||
if (!await launchSimulator(<String>['-n'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Run again to force it to Foreground (using -n doesn't force existing
|
||||
// devices to the foreground)
|
||||
await launchSimulator(<String>[]);
|
||||
return _simulator.boot();
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the list of iOS Simulators (there can only be zero or one).
|
||||
List<IOSEmulator> getEmulators() {
|
||||
final String simulatorPath = globals.xcode.getSimulatorPath();
|
||||
if (simulatorPath == null) {
|
||||
return <IOSEmulator>[];
|
||||
}
|
||||
|
||||
return <IOSEmulator>[const IOSEmulator(iosSimulatorId)];
|
||||
}
|
||||
|
|
|
@ -66,7 +66,9 @@ class IOSSimulatorUtils {
|
|||
return <IOSSimulator>[];
|
||||
}
|
||||
|
||||
final List<SimDevice> connected = await _simControl.getConnectedDevices();
|
||||
final List<SimDevice> connected = (await _simControl.getAvailableDevices())
|
||||
.where((SimDevice device) => device.isBooted)
|
||||
.toList();
|
||||
return connected.map<IOSSimulator>((SimDevice device) {
|
||||
return IOSSimulator(
|
||||
device.udid,
|
||||
|
@ -77,6 +79,26 @@ class IOSSimulatorUtils {
|
|||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
Future<List<IOSSimulator>> getAvailableDevices() async {
|
||||
if (!_xcode.isInstalledAndMeetsVersionCheck) {
|
||||
return <IOSSimulator>[];
|
||||
}
|
||||
|
||||
final List<SimDevice> available = await _simControl.getAvailableDevices();
|
||||
return available
|
||||
.map<IOSSimulator>((SimDevice device) {
|
||||
return IOSSimulator(
|
||||
device.udid,
|
||||
name: device.name,
|
||||
simControl: _simControl,
|
||||
simulatorCategory: device.category,
|
||||
xcode: _xcode,
|
||||
);
|
||||
})
|
||||
.where((IOSSimulator simulator) => simulator.isSupported())
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around the `simctl` command line tool.
|
||||
|
@ -89,6 +111,23 @@ class SimControl {
|
|||
_xcode = xcode,
|
||||
_processUtils = ProcessUtils(processManager: processManager, logger: logger);
|
||||
|
||||
/// Create a [SimControl] for testing.
|
||||
///
|
||||
/// Defaults to a buffer logger.
|
||||
@visibleForTesting
|
||||
factory SimControl.test({
|
||||
@required ProcessManager processManager,
|
||||
Logger logger,
|
||||
Xcode xcode,
|
||||
}) {
|
||||
logger ??= BufferLogger.test();
|
||||
return SimControl(
|
||||
logger: logger,
|
||||
xcode: xcode,
|
||||
processManager: processManager,
|
||||
);
|
||||
}
|
||||
|
||||
final Logger _logger;
|
||||
final ProcessUtils _processUtils;
|
||||
final Xcode _xcode;
|
||||
|
@ -160,10 +199,10 @@ class SimControl {
|
|||
return devices;
|
||||
}
|
||||
|
||||
/// Returns all the connected simulator devices.
|
||||
Future<List<SimDevice>> getConnectedDevices() async {
|
||||
/// Returns all the available simulator devices.
|
||||
Future<List<SimDevice>> getAvailableDevices() async {
|
||||
final List<SimDevice> simDevices = await getDevices();
|
||||
return simDevices.where((SimDevice device) => device.isBooted).toList();
|
||||
return simDevices.where((SimDevice device) => device.isAvailable).toList();
|
||||
}
|
||||
|
||||
Future<bool> isInstalled(String deviceId, String appId) {
|
||||
|
@ -234,6 +273,17 @@ class SimControl {
|
|||
return result;
|
||||
}
|
||||
|
||||
Future<RunResult> boot(String deviceId) {
|
||||
return _processUtils.run(
|
||||
<String>[
|
||||
..._xcode.xcrunCommand(),
|
||||
'simctl',
|
||||
'boot',
|
||||
deviceId,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> takeScreenshot(String deviceId, String outputPath) async {
|
||||
try {
|
||||
await _processUtils.run(
|
||||
|
@ -296,7 +346,11 @@ class SimDevice {
|
|||
final Map<String, dynamic> data;
|
||||
|
||||
String get state => data['state']?.toString();
|
||||
String get availability => data['availability']?.toString();
|
||||
|
||||
bool get isAvailable =>
|
||||
data['isAvailable'] == true ||
|
||||
data['availability']?.toString() == '(available)';
|
||||
|
||||
String get name => data['name']?.toString();
|
||||
String get udid => data['udid']?.toString();
|
||||
|
||||
|
@ -394,7 +448,6 @@ class IOSSimulator extends Device {
|
|||
@override
|
||||
bool isSupported() {
|
||||
if (!globals.platform.isMacOS) {
|
||||
_supportMessage = 'iOS devices require a Mac host machine.';
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -402,21 +455,25 @@ class IOSSimulator extends Device {
|
|||
// We do not yet support WatchOS or tvOS devices.
|
||||
final RegExp blocklist = RegExp(r'Apple (TV|Watch)', caseSensitive: false);
|
||||
if (blocklist.hasMatch(name)) {
|
||||
_supportMessage = 'Flutter does not support Apple TV or Apple Watch.';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
String _supportMessage;
|
||||
Future<bool> boot() async {
|
||||
final RunResult result = await _simControl.boot(id);
|
||||
|
||||
@override
|
||||
String supportMessage() {
|
||||
if (isSupported()) {
|
||||
return 'Supported';
|
||||
if (result.exitCode == 0) {
|
||||
return true;
|
||||
}
|
||||
// 149 exit code means the device is already booted. Ignore this error.
|
||||
if (result.exitCode == 149) {
|
||||
globals.printTrace('Simulator "$id" already booted.');
|
||||
return true;
|
||||
}
|
||||
|
||||
return _supportMessage ?? 'Unknown';
|
||||
globals.logger.printError('$result');
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -71,7 +71,7 @@ void main() {
|
|||
expect(emulator.name, displayName);
|
||||
expect(emulator.manufacturer, manufacturer);
|
||||
expect(emulator.category, Category.mobile);
|
||||
expect(emulator.platformType, PlatformType.android);
|
||||
expect(emulator.platformDisplay, 'android');
|
||||
});
|
||||
|
||||
testWithoutContext('prefers displayname for name', () {
|
||||
|
|
|
@ -2,15 +2,13 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/android/android_workflow.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/emulator.dart';
|
||||
import 'package:flutter_tools/src/ios/ios_emulators.dart';
|
||||
import 'package:flutter_tools/src/ios/simulators.dart';
|
||||
import 'package:flutter_tools/src/macos/xcode.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:process/process.dart';
|
||||
|
@ -45,14 +43,10 @@ const FakeCommand kListEmulatorsCommand = FakeCommand(
|
|||
);
|
||||
|
||||
void main() {
|
||||
MockProcessManager mockProcessManager;
|
||||
MockAndroidSdk mockSdk;
|
||||
MockXcode mockXcode;
|
||||
|
||||
setUp(() {
|
||||
mockProcessManager = MockProcessManager();
|
||||
mockSdk = MockAndroidSdk();
|
||||
mockXcode = MockXcode();
|
||||
|
||||
when(mockSdk.avdManagerPath).thenReturn('avdmanager');
|
||||
when(mockSdk.getAvdManagerPath()).thenReturn('avdmanager');
|
||||
|
@ -299,24 +293,53 @@ void main() {
|
|||
});
|
||||
|
||||
group('ios_emulators', () {
|
||||
bool didAttemptToRunSimulator = false;
|
||||
MockXcode mockXcode;
|
||||
FakeProcessManager fakeProcessManager;
|
||||
|
||||
setUp(() {
|
||||
when(mockXcode.xcodeSelectPath).thenReturn('/fake/Xcode.app/Contents/Developer');
|
||||
when(mockXcode.getSimulatorPath()).thenAnswer((_) => '/fake/simulator.app');
|
||||
when(mockProcessManager.run(any)).thenAnswer((Invocation invocation) async {
|
||||
final List<String> args = invocation.positionalArguments[0] as List<String>;
|
||||
if (args.length >= 3 && args[0] == 'open' && args[1] == '-a' && args[2] == '/fake/simulator.app') {
|
||||
didAttemptToRunSimulator = true;
|
||||
}
|
||||
return ProcessResult(101, 0, '', '');
|
||||
});
|
||||
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[]);
|
||||
mockXcode = MockXcode();
|
||||
when(mockXcode.xcrunCommand()).thenReturn(<String>['xcrun']);
|
||||
when(mockXcode.getSimulatorPath())
|
||||
.thenAnswer((_) => '/fake/simulator.app');
|
||||
});
|
||||
|
||||
testUsingContext('runs correct launch commands', () async {
|
||||
const Emulator emulator = IOSEmulator('ios');
|
||||
fakeProcessManager.addCommands(<FakeCommand>[
|
||||
const FakeCommand(command: <String>[
|
||||
'open',
|
||||
'-a',
|
||||
'/fake/simulator.app',
|
||||
]),
|
||||
const FakeCommand(command: <String>[
|
||||
'xcrun',
|
||||
'simctl',
|
||||
'boot',
|
||||
'1234',
|
||||
]),
|
||||
]);
|
||||
final SimControl simControl = SimControl.test(
|
||||
processManager: fakeProcessManager,
|
||||
xcode: mockXcode,
|
||||
);
|
||||
|
||||
final IOSSimulator simulator = IOSSimulator(
|
||||
'1234',
|
||||
name: 'iPhone 12',
|
||||
simulatorCategory: 'com.apple.CoreSimulator.SimRuntime.iOS-14-3',
|
||||
simControl: simControl,
|
||||
xcode: mockXcode,
|
||||
);
|
||||
final IOSEmulator emulator = IOSEmulator(simulator);
|
||||
|
||||
expect(emulator.id, '1234');
|
||||
expect(emulator.name, 'iPhone 12');
|
||||
expect(emulator.category, Category.mobile);
|
||||
expect(emulator.platformDisplay, 'iOS-14-3');
|
||||
await emulator.launch();
|
||||
expect(didAttemptToRunSimulator, equals(true));
|
||||
expect(fakeProcessManager.hasRemainingExpectations, false);
|
||||
}, overrides: <Type, Generator>{
|
||||
ProcessManager: () => mockProcessManager,
|
||||
ProcessManager: () => fakeProcessManager,
|
||||
Xcode: () => mockXcode,
|
||||
});
|
||||
});
|
||||
|
@ -347,35 +370,11 @@ class FakeEmulator extends Emulator {
|
|||
Category get category => Category.mobile;
|
||||
|
||||
@override
|
||||
PlatformType get platformType => PlatformType.android;
|
||||
String get platformDisplay => PlatformType.android.toString();
|
||||
|
||||
@override
|
||||
Future<void> launch() {
|
||||
throw UnimplementedError('Not implemented in Mock');
|
||||
}
|
||||
}
|
||||
|
||||
class MockProcessManager extends Mock implements ProcessManager {
|
||||
|
||||
@override
|
||||
ProcessResult runSync(
|
||||
List<dynamic> command, {
|
||||
String workingDirectory,
|
||||
Map<String, String> environment,
|
||||
bool includeParentEnvironment = true,
|
||||
bool runInShell = false,
|
||||
Encoding stdoutEncoding = systemEncoding,
|
||||
Encoding stderrEncoding = systemEncoding,
|
||||
}) {
|
||||
final String program = command[0] as String;
|
||||
final List<String> args = command.sublist(1) as List<String>;
|
||||
switch (program) {
|
||||
case '/usr/bin/xcode-select':
|
||||
throw ProcessException(program, args);
|
||||
break;
|
||||
}
|
||||
throw StateError('Unexpected process call: $command');
|
||||
}
|
||||
}
|
||||
|
||||
class MockXcode extends Mock implements Xcode {}
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
|
|||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/base/process.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/build_system/build_system.dart';
|
||||
import 'package:flutter_tools/src/devfs.dart';
|
||||
|
@ -785,12 +786,19 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text'''
|
|||
"availability" : "(available)",
|
||||
"name" : "iPhone 5s",
|
||||
"udid" : "TEST-PHONE-UDID"
|
||||
},
|
||||
{
|
||||
"state" : "Shutdown",
|
||||
"isAvailable" : false,
|
||||
"name" : "iPhone 11",
|
||||
"udid" : "TEST-PHONE-UNAVAILABLE-UDID",
|
||||
"availabilityError" : "runtime profile not found"
|
||||
}
|
||||
],
|
||||
"tvOS 11.4" : [
|
||||
{
|
||||
"state" : "Shutdown",
|
||||
"availability" : "(available)",
|
||||
"isAvailable" : true,
|
||||
"name" : "Apple TV",
|
||||
"udid" : "TEST-TV-UDID"
|
||||
}
|
||||
|
@ -824,11 +832,12 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text'''
|
|||
|
||||
testWithoutContext('getDevices succeeds', () async {
|
||||
final List<SimDevice> devices = await simControl.getDevices();
|
||||
expect(devices.length, 4);
|
||||
|
||||
final SimDevice watch = devices[0];
|
||||
expect(watch.category, 'watchOS 4.3');
|
||||
expect(watch.state, 'Shutdown');
|
||||
expect(watch.availability, '(available)');
|
||||
expect(watch.isAvailable, true);
|
||||
expect(watch.name, 'Apple Watch - 38mm');
|
||||
expect(watch.udid, 'TEST-WATCH-UDID');
|
||||
expect(watch.isBooted, isFalse);
|
||||
|
@ -836,20 +845,33 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text'''
|
|||
final SimDevice phone = devices[1];
|
||||
expect(phone.category, 'iOS 11.4');
|
||||
expect(phone.state, 'Booted');
|
||||
expect(phone.availability, '(available)');
|
||||
expect(phone.isAvailable, true);
|
||||
expect(phone.name, 'iPhone 5s');
|
||||
expect(phone.udid, 'TEST-PHONE-UDID');
|
||||
expect(phone.isBooted, isTrue);
|
||||
|
||||
final SimDevice tv = devices[2];
|
||||
final SimDevice unavailablePhone = devices[2];
|
||||
expect(unavailablePhone.category, 'iOS 11.4');
|
||||
expect(unavailablePhone.state, 'Shutdown');
|
||||
expect(unavailablePhone.isAvailable, isFalse);
|
||||
expect(unavailablePhone.name, 'iPhone 11');
|
||||
expect(unavailablePhone.udid, 'TEST-PHONE-UNAVAILABLE-UDID');
|
||||
expect(unavailablePhone.isBooted, isFalse);
|
||||
|
||||
final SimDevice tv = devices[3];
|
||||
expect(tv.category, 'tvOS 11.4');
|
||||
expect(tv.state, 'Shutdown');
|
||||
expect(tv.availability, '(available)');
|
||||
expect(tv.isAvailable, true);
|
||||
expect(tv.name, 'Apple TV');
|
||||
expect(tv.udid, 'TEST-TV-UDID');
|
||||
expect(tv.isBooted, isFalse);
|
||||
});
|
||||
|
||||
testWithoutContext('getAvailableDevices succeeds', () async {
|
||||
final List<SimDevice> devices = await simControl.getAvailableDevices();
|
||||
expect(devices.length, 3);
|
||||
});
|
||||
|
||||
testWithoutContext('getDevices handles bad simctl output', () async {
|
||||
when(mockProcessManager.run(any))
|
||||
.thenAnswer((Invocation _) async => ProcessResult(mockPid, 0, 'Install Started', ''));
|
||||
|
@ -905,6 +927,78 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text'''
|
|||
throwsToolExit(message: r'Unable to launch'),
|
||||
);
|
||||
});
|
||||
|
||||
testWithoutContext('.boot() calls the right command', () async {
|
||||
await simControl.boot(deviceId);
|
||||
verify(mockProcessManager.run(
|
||||
<String>['xcrun', 'simctl', 'boot', deviceId],
|
||||
environment: anyNamed('environment'),
|
||||
workingDirectory: anyNamed('workingDirectory'),
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
group('boot', () {
|
||||
SimControl simControl;
|
||||
MockXcode mockXcode;
|
||||
|
||||
setUp(() {
|
||||
simControl = MockSimControl();
|
||||
mockXcode = MockXcode();
|
||||
when(mockXcode.xcrunCommand()).thenReturn(<String>['xcrun']);
|
||||
});
|
||||
|
||||
testUsingContext('success', () async {
|
||||
final IOSSimulator device = IOSSimulator(
|
||||
'x',
|
||||
name: 'iPhone SE',
|
||||
simulatorCategory: 'iOS 11.2',
|
||||
simControl: simControl,
|
||||
xcode: mockXcode,
|
||||
);
|
||||
when(simControl.boot(any)).thenAnswer((_) async =>
|
||||
RunResult(ProcessResult(0, 0, '', ''), <String>['simctl']));
|
||||
|
||||
expect(await device.boot(), isTrue);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('already booted', () async {
|
||||
final IOSSimulator device = IOSSimulator(
|
||||
'x',
|
||||
name: 'iPhone SE',
|
||||
simulatorCategory: 'iOS 11.2',
|
||||
simControl: simControl,
|
||||
xcode: mockXcode,
|
||||
);
|
||||
// 149 means the device is already booted.
|
||||
when(simControl.boot(any)).thenAnswer((_) async =>
|
||||
RunResult(ProcessResult(0, 149, '', ''), <String>['simctl']));
|
||||
|
||||
expect(await device.boot(), isTrue);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('failed', () async {
|
||||
final IOSSimulator device = IOSSimulator(
|
||||
'x',
|
||||
name: 'iPhone SE',
|
||||
simulatorCategory: 'iOS 11.2',
|
||||
simControl: simControl,
|
||||
xcode: mockXcode,
|
||||
);
|
||||
when(simControl.boot(any)).thenAnswer((_) async =>
|
||||
RunResult(ProcessResult(0, 1, '', ''), <String>['simctl']));
|
||||
|
||||
expect(await device.boot(), isFalse);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
});
|
||||
|
||||
group('startApp', () {
|
||||
|
|
|
@ -114,6 +114,7 @@ void testUsingContext(
|
|||
IOSSimulatorUtils: () {
|
||||
final MockIOSSimulatorUtils mock = MockIOSSimulatorUtils();
|
||||
when(mock.getAttachedDevices()).thenAnswer((Invocation _) async => <IOSSimulator>[]);
|
||||
when(mock.getAvailableDevices()).thenAnswer((Invocation _) async => <IOSSimulator>[]);
|
||||
return mock;
|
||||
},
|
||||
OutputPreferences: () => OutputPreferences.test(),
|
||||
|
@ -286,7 +287,7 @@ class FakeDoctor extends Doctor {
|
|||
|
||||
class MockSimControl extends Mock implements SimControl {
|
||||
MockSimControl() {
|
||||
when(getConnectedDevices()).thenAnswer((Invocation _) async => <SimDevice>[]);
|
||||
when(getAvailableDevices()).thenAnswer((Invocation _) async => <SimDevice>[]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue