mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
588 lines
20 KiB
Dart
588 lines
20 KiB
Dart
// Copyright 2014 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.
|
|
|
|
// @dart = 2.8
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:file/file.dart';
|
|
import 'package:file/memory.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/base/logger.dart';
|
|
import 'package:flutter_tools/src/base/os.dart';
|
|
import 'package:flutter_tools/src/base/platform.dart';
|
|
import 'package:flutter_tools/src/build_info.dart';
|
|
import 'package:flutter_tools/src/cache.dart';
|
|
import 'package:flutter_tools/src/device.dart';
|
|
import 'package:flutter_tools/src/device_port_forwarder.dart';
|
|
import 'package:flutter_tools/src/ios/application_package.dart';
|
|
import 'package:flutter_tools/src/ios/devices.dart';
|
|
import 'package:flutter_tools/src/ios/ios_deploy.dart';
|
|
import 'package:flutter_tools/src/ios/ios_workflow.dart';
|
|
import 'package:flutter_tools/src/ios/iproxy.dart';
|
|
import 'package:flutter_tools/src/ios/mac.dart';
|
|
import 'package:flutter_tools/src/macos/xcode.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
|
|
import '../../src/common.dart';
|
|
import '../../src/context.dart';
|
|
|
|
void main() {
|
|
final FakePlatform macPlatform = FakePlatform(operatingSystem: 'macos');
|
|
final FakePlatform linuxPlatform = FakePlatform(operatingSystem: 'linux');
|
|
final FakePlatform windowsPlatform = FakePlatform(operatingSystem: 'windows');
|
|
|
|
group('IOSDevice', () {
|
|
final List<Platform> unsupportedPlatforms = <Platform>[linuxPlatform, windowsPlatform];
|
|
Cache cache;
|
|
Logger logger;
|
|
IOSDeploy iosDeploy;
|
|
IMobileDevice iMobileDevice;
|
|
FileSystem nullFileSystem;
|
|
|
|
setUp(() {
|
|
final Artifacts artifacts = Artifacts.test();
|
|
cache = Cache.test();
|
|
logger = BufferLogger.test();
|
|
iosDeploy = IOSDeploy(
|
|
artifacts: artifacts,
|
|
cache: cache,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
iMobileDevice = IMobileDevice(
|
|
artifacts: artifacts,
|
|
cache: cache,
|
|
logger: logger,
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
});
|
|
|
|
testWithoutContext('successfully instantiates on Mac OS', () {
|
|
IOSDevice(
|
|
'device-123',
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
name: 'iPhone 1',
|
|
sdkVersion: '13.3',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
);
|
|
});
|
|
|
|
testWithoutContext('parses major version', () {
|
|
expect(IOSDevice(
|
|
'device-123',
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
name: 'iPhone 1',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
sdkVersion: '1.0.0',
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
).majorSdkVersion, 1);
|
|
expect(IOSDevice(
|
|
'device-123',
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
name: 'iPhone 1',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
sdkVersion: '13.1.1',
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
).majorSdkVersion, 13);
|
|
expect(IOSDevice(
|
|
'device-123',
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
name: 'iPhone 1',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
sdkVersion: '10',
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
).majorSdkVersion, 10);
|
|
expect(IOSDevice(
|
|
'device-123',
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
name: 'iPhone 1',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
sdkVersion: '0',
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
).majorSdkVersion, 0);
|
|
expect(IOSDevice(
|
|
'device-123',
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
name: 'iPhone 1',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
sdkVersion: 'bogus',
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
).majorSdkVersion, 0);
|
|
});
|
|
|
|
testWithoutContext('Supports debug, profile, and release modes', () {
|
|
final IOSDevice device = IOSDevice(
|
|
'device-123',
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
name: 'iPhone 1',
|
|
sdkVersion: '13.3',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
);
|
|
|
|
expect(device.supportsRuntimeMode(BuildMode.debug), true);
|
|
expect(device.supportsRuntimeMode(BuildMode.profile), true);
|
|
expect(device.supportsRuntimeMode(BuildMode.release), true);
|
|
expect(device.supportsRuntimeMode(BuildMode.jitRelease), false);
|
|
});
|
|
|
|
for (final Platform platform in unsupportedPlatforms) {
|
|
testWithoutContext('throws UnsupportedError exception if instantiated on ${platform.operatingSystem}', () {
|
|
expect(
|
|
() {
|
|
IOSDevice(
|
|
'device-123',
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: platform,
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
name: 'iPhone 1',
|
|
sdkVersion: '13.3',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
);
|
|
},
|
|
throwsAssertionError,
|
|
);
|
|
});
|
|
}
|
|
|
|
group('.dispose()', () {
|
|
IOSDevice device;
|
|
MockIOSApp appPackage1;
|
|
MockIOSApp appPackage2;
|
|
IOSDeviceLogReader logReader1;
|
|
IOSDeviceLogReader logReader2;
|
|
MockProcess mockProcess1;
|
|
MockProcess mockProcess2;
|
|
MockProcess mockProcess3;
|
|
IOSDevicePortForwarder portForwarder;
|
|
ForwardedPort forwardedPort;
|
|
Cache cache;
|
|
Logger logger;
|
|
IOSDeploy iosDeploy;
|
|
FileSystem nullFileSystem;
|
|
IProxy iproxy;
|
|
|
|
IOSDevicePortForwarder createPortForwarder(
|
|
ForwardedPort forwardedPort,
|
|
IOSDevice device) {
|
|
iproxy = IProxy.test(logger: logger, processManager: FakeProcessManager.any());
|
|
final IOSDevicePortForwarder portForwarder = IOSDevicePortForwarder(
|
|
id: device.id,
|
|
logger: logger,
|
|
operatingSystemUtils: OperatingSystemUtils(
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: FakePlatform(operatingSystem: 'macos'),
|
|
processManager: FakeProcessManager.any(),
|
|
),
|
|
iproxy: iproxy,
|
|
);
|
|
portForwarder.addForwardedPorts(<ForwardedPort>[forwardedPort]);
|
|
return portForwarder;
|
|
}
|
|
|
|
IOSDeviceLogReader createLogReader(
|
|
IOSDevice device,
|
|
IOSApp appPackage,
|
|
Process process) {
|
|
final IOSDeviceLogReader logReader = IOSDeviceLogReader.create(
|
|
device: device,
|
|
app: appPackage,
|
|
iMobileDevice: null, // not used by this test.
|
|
);
|
|
logReader.idevicesyslogProcess = process;
|
|
return logReader;
|
|
}
|
|
|
|
setUp(() {
|
|
appPackage1 = MockIOSApp();
|
|
appPackage2 = MockIOSApp();
|
|
when(appPackage1.name).thenReturn('flutterApp1');
|
|
when(appPackage2.name).thenReturn('flutterApp2');
|
|
mockProcess1 = MockProcess();
|
|
mockProcess2 = MockProcess();
|
|
mockProcess3 = MockProcess();
|
|
forwardedPort = ForwardedPort.withContext(123, 456, mockProcess3);
|
|
cache = Cache.test();
|
|
iosDeploy = IOSDeploy(
|
|
artifacts: Artifacts.test(),
|
|
cache: cache,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
});
|
|
|
|
testWithoutContext('kills all log readers & port forwarders', () async {
|
|
device = IOSDevice(
|
|
'123',
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
fileSystem: nullFileSystem,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
name: 'iPhone 1',
|
|
sdkVersion: '13.3',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
);
|
|
logReader1 = createLogReader(device, appPackage1, mockProcess1);
|
|
logReader2 = createLogReader(device, appPackage2, mockProcess2);
|
|
portForwarder = createPortForwarder(forwardedPort, device);
|
|
device.setLogReader(appPackage1, logReader1);
|
|
device.setLogReader(appPackage2, logReader2);
|
|
device.portForwarder = portForwarder;
|
|
|
|
await device.dispose();
|
|
|
|
verify(mockProcess1.kill());
|
|
verify(mockProcess2.kill());
|
|
verify(mockProcess3.kill());
|
|
});
|
|
});
|
|
});
|
|
|
|
group('polling', () {
|
|
MockXcdevice mockXcdevice;
|
|
Cache cache;
|
|
FakeProcessManager fakeProcessManager;
|
|
BufferLogger logger;
|
|
IOSDeploy iosDeploy;
|
|
IMobileDevice iMobileDevice;
|
|
IOSWorkflow mockIosWorkflow;
|
|
IOSDevice device1;
|
|
IOSDevice device2;
|
|
|
|
setUp(() {
|
|
mockXcdevice = MockXcdevice();
|
|
final Artifacts artifacts = Artifacts.test();
|
|
cache = Cache.test();
|
|
logger = BufferLogger.test();
|
|
mockIosWorkflow = MockIOSWorkflow();
|
|
fakeProcessManager = FakeProcessManager.any();
|
|
iosDeploy = IOSDeploy(
|
|
artifacts: artifacts,
|
|
cache: cache,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
processManager: fakeProcessManager,
|
|
);
|
|
iMobileDevice = IMobileDevice(
|
|
artifacts: artifacts,
|
|
cache: cache,
|
|
processManager: fakeProcessManager,
|
|
logger: logger,
|
|
);
|
|
|
|
device1 = IOSDevice(
|
|
'd83d5bc53967baa0ee18626ba87b6254b2ab5418',
|
|
name: 'Paired iPhone',
|
|
sdkVersion: '13.3',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
fileSystem: MemoryFileSystem.test(),
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
);
|
|
|
|
device2 = IOSDevice(
|
|
'00008027-00192736010F802E',
|
|
name: 'iPad Pro',
|
|
sdkVersion: '13.3',
|
|
cpuArchitecture: DarwinArch.arm64,
|
|
iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()),
|
|
iosDeploy: iosDeploy,
|
|
iMobileDevice: iMobileDevice,
|
|
logger: logger,
|
|
platform: macPlatform,
|
|
fileSystem: MemoryFileSystem.test(),
|
|
interfaceType: IOSDeviceInterface.usb,
|
|
);
|
|
});
|
|
|
|
testWithoutContext('start polling without Xcode', () async {
|
|
final IOSDevices iosDevices = IOSDevices(
|
|
platform: macPlatform,
|
|
xcdevice: mockXcdevice,
|
|
iosWorkflow: mockIosWorkflow,
|
|
logger: logger,
|
|
);
|
|
when(mockXcdevice.isInstalled).thenReturn(false);
|
|
|
|
await iosDevices.startPolling();
|
|
verifyNever(mockXcdevice.getAvailableIOSDevices());
|
|
});
|
|
|
|
testWithoutContext('start polling', () async {
|
|
final IOSDevices iosDevices = IOSDevices(
|
|
platform: macPlatform,
|
|
xcdevice: mockXcdevice,
|
|
iosWorkflow: mockIosWorkflow,
|
|
logger: logger,
|
|
);
|
|
when(mockXcdevice.isInstalled).thenReturn(true);
|
|
|
|
int fetchDevicesCount = 0;
|
|
when(mockXcdevice.getAvailableIOSDevices())
|
|
.thenAnswer((Invocation invocation) {
|
|
if (fetchDevicesCount == 0) {
|
|
// Initial time, no devices.
|
|
fetchDevicesCount++;
|
|
return Future<List<IOSDevice>>.value(<IOSDevice>[]);
|
|
} else if (fetchDevicesCount == 1) {
|
|
// Simulate 2 devices added later.
|
|
fetchDevicesCount++;
|
|
return Future<List<IOSDevice>>.value(<IOSDevice>[device1, device2]);
|
|
}
|
|
fail('Too many calls to getAvailableTetheredIOSDevices');
|
|
});
|
|
|
|
int addedCount = 0;
|
|
final Completer<void> added = Completer<void>();
|
|
iosDevices.onAdded.listen((Device device) {
|
|
addedCount++;
|
|
// 2 devices will be added.
|
|
// Will throw over-completion if called more than twice.
|
|
if (addedCount >= 2) {
|
|
added.complete();
|
|
}
|
|
});
|
|
|
|
final Completer<void> removed = Completer<void>();
|
|
iosDevices.onRemoved.listen((Device device) {
|
|
// Will throw over-completion if called more than once.
|
|
removed.complete();
|
|
});
|
|
|
|
final StreamController<Map<XCDeviceEvent, String>> eventStream = StreamController<Map<XCDeviceEvent, String>>();
|
|
when(mockXcdevice.observedDeviceEvents()).thenAnswer((_) => eventStream.stream);
|
|
|
|
await iosDevices.startPolling();
|
|
verify(mockXcdevice.getAvailableIOSDevices()).called(1);
|
|
|
|
expect(iosDevices.deviceNotifier.items, isEmpty);
|
|
expect(eventStream.hasListener, isTrue);
|
|
|
|
eventStream.add(<XCDeviceEvent, String>{
|
|
XCDeviceEvent.attach: 'd83d5bc53967baa0ee18626ba87b6254b2ab5418'
|
|
});
|
|
await added.future;
|
|
expect(iosDevices.deviceNotifier.items.length, 2);
|
|
expect(iosDevices.deviceNotifier.items, contains(device1));
|
|
expect(iosDevices.deviceNotifier.items, contains(device2));
|
|
|
|
eventStream.add(<XCDeviceEvent, String>{
|
|
XCDeviceEvent.detach: 'd83d5bc53967baa0ee18626ba87b6254b2ab5418'
|
|
});
|
|
await removed.future;
|
|
expect(iosDevices.deviceNotifier.items, <Device>[device2]);
|
|
|
|
// Remove stream will throw over-completion if called more than once
|
|
// which proves this is ignored.
|
|
eventStream.add(<XCDeviceEvent, String>{
|
|
XCDeviceEvent.detach: 'bogus'
|
|
});
|
|
|
|
expect(addedCount, 2);
|
|
|
|
await iosDevices.stopPolling();
|
|
|
|
expect(eventStream.hasListener, isFalse);
|
|
});
|
|
|
|
testWithoutContext('polling can be restarted if stream is closed', () async {
|
|
final IOSDevices iosDevices = IOSDevices(
|
|
platform: macPlatform,
|
|
xcdevice: mockXcdevice,
|
|
iosWorkflow: mockIosWorkflow,
|
|
logger: logger,
|
|
);
|
|
when(mockXcdevice.isInstalled).thenReturn(true);
|
|
|
|
when(mockXcdevice.getAvailableIOSDevices())
|
|
.thenAnswer((Invocation invocation) => Future<List<IOSDevice>>.value(<IOSDevice>[]));
|
|
|
|
final StreamController<Map<XCDeviceEvent, String>> eventStream = StreamController<Map<XCDeviceEvent, String>>();
|
|
final StreamController<Map<XCDeviceEvent, String>> rescheduledStream = StreamController<Map<XCDeviceEvent, String>>();
|
|
|
|
bool reschedule = false;
|
|
when(mockXcdevice.observedDeviceEvents()).thenAnswer((Invocation invocation) {
|
|
if (!reschedule) {
|
|
reschedule = true;
|
|
return eventStream.stream;
|
|
}
|
|
return rescheduledStream.stream;
|
|
});
|
|
|
|
await iosDevices.startPolling();
|
|
expect(eventStream.hasListener, isTrue);
|
|
verify(mockXcdevice.getAvailableIOSDevices()).called(1);
|
|
|
|
// Pretend xcdevice crashed.
|
|
await eventStream.close();
|
|
expect(logger.traceText, contains('xcdevice observe stopped'));
|
|
|
|
// Confirm a restart still gets streamed events.
|
|
await iosDevices.startPolling();
|
|
|
|
expect(eventStream.hasListener, isFalse);
|
|
expect(rescheduledStream.hasListener, isTrue);
|
|
|
|
await iosDevices.stopPolling();
|
|
expect(rescheduledStream.hasListener, isFalse);
|
|
});
|
|
|
|
testWithoutContext('dispose cancels polling subscription', () async {
|
|
final IOSDevices iosDevices = IOSDevices(
|
|
platform: macPlatform,
|
|
xcdevice: mockXcdevice,
|
|
iosWorkflow: mockIosWorkflow,
|
|
logger: logger,
|
|
);
|
|
when(mockXcdevice.isInstalled).thenReturn(true);
|
|
when(mockXcdevice.getAvailableIOSDevices())
|
|
.thenAnswer((Invocation invocation) => Future<List<IOSDevice>>.value(<IOSDevice>[]));
|
|
|
|
final StreamController<Map<XCDeviceEvent, String>> eventStream = StreamController<Map<XCDeviceEvent, String>>();
|
|
when(mockXcdevice.observedDeviceEvents()).thenAnswer((_) => eventStream.stream);
|
|
|
|
await iosDevices.startPolling();
|
|
expect(iosDevices.deviceNotifier.items, isEmpty);
|
|
expect(eventStream.hasListener, isTrue);
|
|
|
|
iosDevices.dispose();
|
|
expect(eventStream.hasListener, isFalse);
|
|
});
|
|
|
|
final List<Platform> unsupportedPlatforms = <Platform>[linuxPlatform, windowsPlatform];
|
|
for (final Platform unsupportedPlatform in unsupportedPlatforms) {
|
|
testWithoutContext('pollingGetDevices throws Unsupported Operation exception on ${unsupportedPlatform.operatingSystem}', () async {
|
|
final IOSDevices iosDevices = IOSDevices(
|
|
platform: unsupportedPlatform,
|
|
xcdevice: mockXcdevice,
|
|
iosWorkflow: mockIosWorkflow,
|
|
logger: logger,
|
|
);
|
|
when(mockXcdevice.isInstalled).thenReturn(false);
|
|
expect(
|
|
() async { await iosDevices.pollingGetDevices(); },
|
|
throwsA(isA<UnsupportedError>()),
|
|
);
|
|
});
|
|
}
|
|
|
|
testWithoutContext('pollingGetDevices returns attached devices', () async {
|
|
final IOSDevices iosDevices = IOSDevices(
|
|
platform: macPlatform,
|
|
xcdevice: mockXcdevice,
|
|
iosWorkflow: mockIosWorkflow,
|
|
logger: logger,
|
|
);
|
|
when(mockXcdevice.isInstalled).thenReturn(true);
|
|
|
|
when(mockXcdevice.getAvailableIOSDevices())
|
|
.thenAnswer((Invocation invocation) => Future<List<IOSDevice>>.value(<IOSDevice>[device1]));
|
|
|
|
final List<Device> devices = await iosDevices.pollingGetDevices();
|
|
expect(devices, hasLength(1));
|
|
expect(identical(devices.first, device1), isTrue);
|
|
});
|
|
});
|
|
|
|
group('getDiagnostics', () {
|
|
MockXcdevice mockXcdevice;
|
|
IOSWorkflow mockIosWorkflow;
|
|
Logger logger;
|
|
|
|
setUp(() {
|
|
mockXcdevice = MockXcdevice();
|
|
mockIosWorkflow = MockIOSWorkflow();
|
|
logger = BufferLogger.test();
|
|
});
|
|
|
|
final List<Platform> unsupportedPlatforms = <Platform>[linuxPlatform, windowsPlatform];
|
|
for (final Platform unsupportedPlatform in unsupportedPlatforms) {
|
|
testWithoutContext('throws returns platform diagnostic exception on ${unsupportedPlatform.operatingSystem}', () async {
|
|
final IOSDevices iosDevices = IOSDevices(
|
|
platform: unsupportedPlatform,
|
|
xcdevice: mockXcdevice,
|
|
iosWorkflow: mockIosWorkflow,
|
|
logger: logger,
|
|
);
|
|
when(mockXcdevice.isInstalled).thenReturn(false);
|
|
expect((await iosDevices.getDiagnostics()).first, 'Control of iOS devices or simulators only supported on macOS.');
|
|
});
|
|
}
|
|
|
|
testWithoutContext('returns diagnostics', () async {
|
|
final IOSDevices iosDevices = IOSDevices(
|
|
platform: macPlatform,
|
|
xcdevice: mockXcdevice,
|
|
iosWorkflow: mockIosWorkflow,
|
|
logger: logger,
|
|
);
|
|
when(mockXcdevice.isInstalled).thenReturn(true);
|
|
when(mockXcdevice.getDiagnostics())
|
|
.thenAnswer((Invocation invocation) => Future<List<String>>.value(<String>['Generic pairing error']));
|
|
|
|
final List<String> diagnostics = await iosDevices.getDiagnostics();
|
|
expect(diagnostics, hasLength(1));
|
|
expect(diagnostics.first, 'Generic pairing error');
|
|
});
|
|
});
|
|
}
|
|
|
|
class MockIOSApp extends Mock implements IOSApp {}
|
|
class MockIOSWorkflow extends Mock implements IOSWorkflow {}
|
|
class MockXcdevice extends Mock implements XCDevice {}
|
|
class MockProcess extends Mock implements Process {}
|