Unverified Commit 674fbd26 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] Ensure flutter daemon clients can detect preview device (#140112)

Part of https://github.com/flutter/flutter/issues/130277
parent 90badf70
...@@ -62,14 +62,22 @@ The `shutdown()` command will terminate the flutter daemon. It is not necessary ...@@ -62,14 +62,22 @@ The `shutdown()` command will terminate the flutter daemon. It is not necessary
#### daemon.getSupportedPlatforms #### daemon.getSupportedPlatforms
The `getSupportedPlatforms()` command will enumerate all platforms supported by the project located at the provided `projectRoot`. It returns a Map with the key 'platforms' containing a List of strings which describe the set of all possibly supported platforms. Possible values include: The `getSupportedPlatforms()` command will enumerate all platforms supported
- android by the project located at the provided `projectRoot`. It returns a Map with
- ios the key 'platformTypes' containing a Map of platform types to a Map with the
- linux #experimental following entries:
- macos #experimental
- windows #experimental - isSupported (bool) - whether or not the platform type is supported
- fuchsia #experimental - reasons (List<Map<String, Object>>, only included if isSupported == false) - a list of reasons why the platform is not supported
- web #experimental
The schema for each element in `reasons` is:
- reasonText (String) - a description of why the platform is not supported
- fixText (String) - human readable instructions of how to fix this reason
- fixCode (String) - stringified version of the `_ReasonCode` enum. To be used
by daemon clients who intend to auto-fix.
The possible platform types are the `PlatformType` enumeration in the lib/src/device.dart library.
#### Events #### Events
......
...@@ -416,36 +416,167 @@ class DaemonDomain extends Domain { ...@@ -416,36 +416,167 @@ class DaemonDomain extends Domain {
/// is correct. /// is correct.
Future<Map<String, Object>> getSupportedPlatforms(Map<String, Object?> args) async { Future<Map<String, Object>> getSupportedPlatforms(Map<String, Object?> args) async {
final String? projectRoot = _getStringArg(args, 'projectRoot', required: true); final String? projectRoot = _getStringArg(args, 'projectRoot', required: true);
final List<String> result = <String>[]; final List<String> platformTypes = <String>[];
final Map<String, Object> platformTypesMap = <String, Object>{};
try { try {
final FlutterProject flutterProject = FlutterProject.fromDirectory(globals.fs.directory(projectRoot)); final FlutterProject flutterProject = FlutterProject.fromDirectory(globals.fs.directory(projectRoot));
final Set<SupportedPlatform> supportedPlatforms = flutterProject.getSupportedPlatforms().toSet(); final Set<SupportedPlatform> supportedPlatforms = flutterProject.getSupportedPlatforms().toSet();
if (featureFlags.isLinuxEnabled && supportedPlatforms.contains(SupportedPlatform.linux)) {
result.add('linux'); void handlePlatformType(
} PlatformType platform,
if (featureFlags.isMacOSEnabled && supportedPlatforms.contains(SupportedPlatform.macos)) { ) {
result.add('macos'); final List<Map<String, Object>> reasons = <Map<String, Object>>[];
} switch (platform) {
if (featureFlags.isWindowsEnabled && supportedPlatforms.contains(SupportedPlatform.windows)) { case PlatformType.linux:
result.add('windows'); if (!featureFlags.isLinuxEnabled) {
} reasons.add(<String, Object>{
if (featureFlags.isIOSEnabled && supportedPlatforms.contains(SupportedPlatform.ios)) { 'reasonText': 'the Linux feature is not enabled',
result.add('ios'); 'fixText': 'Run "flutter config --enable-linux-desktop"',
} 'fixCode': _ReasonCode.config.name,
if (featureFlags.isAndroidEnabled && supportedPlatforms.contains(SupportedPlatform.android)) { });
result.add('android'); }
} if (!supportedPlatforms.contains(SupportedPlatform.linux)) {
if (featureFlags.isWebEnabled && supportedPlatforms.contains(SupportedPlatform.web)) { reasons.add(<String, Object>{
result.add('web'); 'reasonText': 'the Linux platform is not enabled for this project',
} 'fixText': 'Run "flutter create --platforms=linux ." in your application directory',
if (featureFlags.isFuchsiaEnabled && supportedPlatforms.contains(SupportedPlatform.fuchsia)) { 'fixCode': _ReasonCode.create.name,
result.add('fuchsia'); });
} }
if (featureFlags.areCustomDevicesEnabled) { case PlatformType.macos:
result.add('custom'); if (!featureFlags.isMacOSEnabled) {
reasons.add(<String, Object>{
'reasonText': 'the macOS feature is not enabled',
'fixText': 'Run "flutter config --enable-macos-desktop"',
'fixCode': _ReasonCode.config.name,
});
}
if (!supportedPlatforms.contains(SupportedPlatform.macos)) {
reasons.add(<String, Object>{
'reasonText': 'the macOS platform is not enabled for this project',
'fixText': 'Run "flutter create --platforms=macos ." in your application directory',
'fixCode': _ReasonCode.create.name,
});
}
case PlatformType.windows:
if (!featureFlags.isWindowsEnabled) {
reasons.add(<String, Object>{
'reasonText': 'the Windows feature is not enabled',
'fixText': 'Run "flutter config --enable-windows-desktop"',
'fixCode': _ReasonCode.config.name,
});
}
if (!supportedPlatforms.contains(SupportedPlatform.windows)) {
reasons.add(<String, Object>{
'reasonText': 'the Windows platform is not enabled for this project',
'fixText': 'Run "flutter create --platforms=windows ." in your application directory',
'fixCode': _ReasonCode.create.name,
});
}
case PlatformType.ios:
if (!featureFlags.isIOSEnabled) {
reasons.add(<String, Object>{
'reasonText': 'the iOS feature is not enabled',
'fixText': 'Run "flutter config --enable-ios"',
'fixCode': _ReasonCode.config.name,
});
}
if (!supportedPlatforms.contains(SupportedPlatform.ios)) {
reasons.add(<String, Object>{
'reasonText': 'the iOS platform is not enabled for this project',
'fixText': 'Run "flutter create --platforms=ios ." in your application directory',
'fixCode': _ReasonCode.create.name,
});
}
case PlatformType.android:
if (!featureFlags.isAndroidEnabled) {
reasons.add(<String, Object>{
'reasonText': 'the Android feature is not enabled',
'fixText': 'Run "flutter config --enable-android"',
'fixCode': _ReasonCode.config.name,
});
}
if (!supportedPlatforms.contains(SupportedPlatform.android)) {
reasons.add(<String, Object>{
'reasonText': 'the Android platform is not enabled for this project',
'fixText': 'Run "flutter create --platforms=android ." in your application directory',
'fixCode': _ReasonCode.create.name,
});
}
case PlatformType.web:
if (!featureFlags.isWebEnabled) {
reasons.add(<String, Object>{
'reasonText': 'the Web feature is not enabled',
'fixText': 'Run "flutter config --enable-web"',
'fixCode': _ReasonCode.config.name,
});
}
if (!supportedPlatforms.contains(SupportedPlatform.web)) {
reasons.add(<String, Object>{
'reasonText': 'the Web platform is not enabled for this project',
'fixText': 'Run "flutter create --platforms=web ." in your application directory',
'fixCode': _ReasonCode.create.name,
});
}
case PlatformType.fuchsia:
if (!featureFlags.isFuchsiaEnabled) {
reasons.add(<String, Object>{
'reasonText': 'the Fuchsia feature is not enabled',
'fixText': 'Run "flutter config --enable-fuchsia"',
'fixCode': _ReasonCode.config.name,
});
}
if (!supportedPlatforms.contains(SupportedPlatform.fuchsia)) {
reasons.add(<String, Object>{
'reasonText': 'the Fuchsia platform is not enabled for this project',
'fixText': 'Run "flutter create --platforms=fuchsia ." in your application directory',
'fixCode': _ReasonCode.create.name,
});
}
case PlatformType.custom:
if (!featureFlags.areCustomDevicesEnabled) {
reasons.add(<String, Object>{
'reasonText': 'the custom devices feature is not enabled',
'fixText': 'Run "flutter config --enable-custom-devices"',
'fixCode': _ReasonCode.config.name,
});
}
case PlatformType.windowsPreview:
// TODO(fujino): detect if there any plugins with native code
if (!featureFlags.isPreviewDeviceEnabled) {
reasons.add(<String, Object>{
'reasonText': 'the Preview Device feature is not enabled',
'fixText': 'Run "flutter config --enable-flutter-preview',
'fixCode': _ReasonCode.config.name,
});
}
if (!supportedPlatforms.contains(SupportedPlatform.windows)) {
reasons.add(<String, Object>{
'reasonText': 'the Windows platform is not enabled for this project',
'fixText': 'Run "flutter create --platforms=windows ." in your application directory',
'fixCode': _ReasonCode.create.name,
});
}
}
if (reasons.isEmpty) {
platformTypes.add(platform.name);
platformTypesMap[platform.name] = const <String, Object>{
'isSupported': true,
};
} else {
platformTypesMap[platform.name] = <String, Object>{
'isSupported': false,
'reasons': reasons,
};
}
} }
PlatformType.values.forEach(handlePlatformType);
return <String, Object>{ return <String, Object>{
'platforms': result, // TODO(fujino): delete this key https://github.com/flutter/flutter/issues/140473
'platforms': platformTypes,
'platformTypes': platformTypesMap,
}; };
} on Exception catch (err, stackTrace) { } on Exception catch (err, stackTrace) {
sendEvent('log', <String, Object?>{ sendEvent('log', <String, Object?>{
...@@ -454,12 +585,16 @@ class DaemonDomain extends Domain { ...@@ -454,12 +585,16 @@ class DaemonDomain extends Domain {
'error': true, 'error': true,
}); });
// On any sort of failure, fall back to Android and iOS for backwards // On any sort of failure, fall back to Android and iOS for backwards
// comparability. // compatibility.
return <String, Object>{ return const <String, Object>{
'platforms': <String>[ 'platforms': <String>[
'android', 'android',
'ios', 'ios',
], ],
'platformTypes': <String, Object>{
'android': <String, Object>{'isSupported': true},
'ios': <String, Object>{'isSupported': true},
},
}; };
} }
} }
...@@ -470,6 +605,14 @@ class DaemonDomain extends Domain { ...@@ -470,6 +605,14 @@ class DaemonDomain extends Domain {
} }
} }
/// The reason a [PlatformType] is not currently supported.
///
/// The [name] of this value will be sent as a response to daemon client.
enum _ReasonCode {
create,
config,
}
typedef RunOrAttach = Future<void> Function({ typedef RunOrAttach = Future<void> Function({
Completer<DebugConnectionInfo>? connectionInfoCompleter, Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void>? appStartedCompleter, Completer<void>? appStartedCompleter,
......
...@@ -45,34 +45,20 @@ enum Category { ...@@ -45,34 +45,20 @@ enum Category {
/// The platform sub-folder that a device type supports. /// The platform sub-folder that a device type supports.
enum PlatformType { enum PlatformType {
web._('web'), web,
android._('android'), android,
ios._('ios'), ios,
linux._('linux'), linux,
macos._('macos'), macos,
windows._('windows'), windows,
fuchsia._('fuchsia'), fuchsia,
custom._('custom'); custom,
windowsPreview;
const PlatformType._(this.value);
final String value;
@override @override
String toString() => value; String toString() => name;
static PlatformType? fromString(String platformType) { static PlatformType? fromString(String platformType) => values.asNameMap()[platformType];
return const <String, PlatformType>{
'web': web,
'android': android,
'ios': ios,
'linux': linux,
'macos': macos,
'windows': windows,
'fuchsia': fuchsia,
'custom': custom,
}[platformType];
}
} }
/// A discovery mechanism for flutter-supported development devices. /// A discovery mechanism for flutter-supported development devices.
......
...@@ -29,7 +29,7 @@ BundleBuilder _defaultBundleBuilder() { ...@@ -29,7 +29,7 @@ BundleBuilder _defaultBundleBuilder() {
return BundleBuilder(); return BundleBuilder();
} }
class PreviewDeviceDiscovery extends DeviceDiscovery { class PreviewDeviceDiscovery extends PollingDeviceDiscovery {
PreviewDeviceDiscovery({ PreviewDeviceDiscovery({
required Platform platform, required Platform platform,
required Artifacts artifacts, required Artifacts artifacts,
...@@ -42,7 +42,8 @@ class PreviewDeviceDiscovery extends DeviceDiscovery { ...@@ -42,7 +42,8 @@ class PreviewDeviceDiscovery extends DeviceDiscovery {
_processManager = processManager, _processManager = processManager,
_fileSystem = fileSystem, _fileSystem = fileSystem,
_platform = platform, _platform = platform,
_features = featureFlags; _features = featureFlags,
super('Flutter preview device');
final Platform _platform; final Platform _platform;
final Artifacts _artifacts; final Artifacts _artifacts;
...@@ -61,9 +62,8 @@ class PreviewDeviceDiscovery extends DeviceDiscovery { ...@@ -61,9 +62,8 @@ class PreviewDeviceDiscovery extends DeviceDiscovery {
List<String> get wellKnownIds => <String>['preview']; List<String> get wellKnownIds => <String>['preview'];
@override @override
Future<List<Device>> devices({ Future<List<Device>> pollingGetDevices({
Duration? timeout, Duration? timeout,
DeviceDiscoveryFilter? filter,
}) async { }) async {
final File previewBinary = _fileSystem.file(_artifacts.getArtifactPath(Artifact.flutterPreviewDevice)); final File previewBinary = _fileSystem.file(_artifacts.getArtifactPath(Artifact.flutterPreviewDevice));
if (!previewBinary.existsSync()) { if (!previewBinary.existsSync()) {
...@@ -76,16 +76,8 @@ class PreviewDeviceDiscovery extends DeviceDiscovery { ...@@ -76,16 +76,8 @@ class PreviewDeviceDiscovery extends DeviceDiscovery {
processManager: _processManager, processManager: _processManager,
previewBinary: previewBinary, previewBinary: previewBinary,
); );
final bool matchesRequirements;
if (!_features.isPreviewDeviceEnabled) {
matchesRequirements = false;
} else if (filter == null) {
matchesRequirements = true;
} else {
matchesRequirements = await filter.matchesRequirements(device);
}
return <Device>[ return <Device>[
if (matchesRequirements) if (_features.isPreviewDeviceEnabled)
device, device,
]; ];
} }
...@@ -114,7 +106,7 @@ class PreviewDevice extends Device { ...@@ -114,7 +106,7 @@ class PreviewDevice extends Device {
_fileSystem = fileSystem, _fileSystem = fileSystem,
_bundleBuilderFactory = builderFactory, _bundleBuilderFactory = builderFactory,
_artifacts = artifacts, _artifacts = artifacts,
super('preview', ephemeral: false, category: Category.desktop, platformType: PlatformType.custom); super('preview', ephemeral: false, category: Category.desktop, platformType: PlatformType.windowsPreview);
final ProcessManager _processManager; final ProcessManager _processManager;
final Logger _logger; final Logger _logger;
...@@ -161,7 +153,7 @@ class PreviewDevice extends Device { ...@@ -161,7 +153,7 @@ class PreviewDevice extends Device {
bool isSupportedForProject(FlutterProject flutterProject) => true; bool isSupportedForProject(FlutterProject flutterProject) => true;
@override @override
String get name => 'preview'; String get name => 'Preview';
@override @override
DevicePortForwarder get portForwarder => const NoOpDevicePortForwarder(); DevicePortForwarder get portForwarder => const NoOpDevicePortForwarder();
......
...@@ -7,10 +7,12 @@ import 'dart:io' as io; ...@@ -7,10 +7,12 @@ import 'dart:io' as io;
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:fake_async/fake_async.dart'; import 'package:fake_async/fake_async.dart';
import 'package:file/memory.dart';
import 'package:file/src/interface/file.dart'; import 'package:file/src/interface/file.dart';
import 'package:flutter_tools/src/android/android_device.dart'; import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/android/android_workflow.dart'; import 'package:flutter_tools/src/android/android_workflow.dart';
import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/dds.dart'; import 'package:flutter_tools/src/base/dds.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/utils.dart'; import 'package:flutter_tools/src/base/utils.dart';
...@@ -22,8 +24,10 @@ import 'package:flutter_tools/src/features.dart'; ...@@ -22,8 +24,10 @@ import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/ios/ios_workflow.dart'; import 'package:flutter_tools/src/ios/ios_workflow.dart';
import 'package:flutter_tools/src/preview_device.dart';
import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/resident_runner.dart';
import 'package:flutter_tools/src/vmservice.dart'; import 'package:flutter_tools/src/vmservice.dart';
import 'package:flutter_tools/src/windows/windows_workflow.dart';
import 'package:test/fake.dart'; import 'package:test/fake.dart';
import '../../src/common.dart'; import '../../src/common.dart';
...@@ -121,10 +125,91 @@ void main() { ...@@ -121,10 +125,91 @@ void main() {
expect(response.data['id'], 0); expect(response.data['id'], 0);
expect(response.data['result'], isNotEmpty); expect(response.data['result'], isNotEmpty);
expect((response.data['result']! as Map<String, Object?>)['platforms'], <String>{'macos'}); expect(
response.data['result']! as Map<String, Object?>,
const <String, Object>{
'platforms': <String>['macos', 'windows', 'windowsPreview'],
'platformTypes': <String, Map<String, Object>>{
'web': <String, Object>{
'isSupported': false,
'reasons': <Map<String, String>>[
<String, String>{
'reasonText': 'the Web feature is not enabled',
'fixText': 'Run "flutter config --enable-web"',
'fixCode': 'config',
},
],
},
'android': <String, Object>{
'isSupported': false,
'reasons': <Map<String, String>>[
<String, String>{
'reasonText': 'the Android feature is not enabled',
'fixText': 'Run "flutter config --enable-android"',
'fixCode': 'config',
},
],
},
'ios': <String, Object>{
'isSupported': false,
'reasons': <Map<String, String>>[
<String, String>{
'reasonText': 'the iOS feature is not enabled',
'fixText': 'Run "flutter config --enable-ios"',
'fixCode': 'config',
},
],
},
'linux': <String, Object>{
'isSupported': false,
'reasons': <Map<String, String>>[
<String, String>{
'reasonText': 'the Linux feature is not enabled',
'fixText': 'Run "flutter config --enable-linux-desktop"',
'fixCode': 'config',
},
],
},
'macos': <String, bool>{'isSupported': true},
'windows': <String, bool>{'isSupported': true},
'fuchsia': <String, Object>{
'isSupported': false,
'reasons': <Map<String, String>>[
<String, String>{
'reasonText': 'the Fuchsia feature is not enabled',
'fixText': 'Run "flutter config --enable-fuchsia"',
'fixCode': 'config',
},
<String, String>{
'reasonText': 'the Fuchsia platform is not enabled for this project',
'fixText': 'Run "flutter create --platforms=fuchsia ." in your application directory',
'fixCode': 'create',
},
],
},
'custom': <String, Object>{
'isSupported': false,
'reasons': <Map<String, String>>[
<String, String>{
'reasonText': 'the custom devices feature is not enabled',
'fixText': 'Run "flutter config --enable-custom-devices"',
'fixCode': 'config',
},
],
},
'windowsPreview': <String, bool>{'isSupported': true},
},
},
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
// Disable Android/iOS and enable macOS to make sure result is consistent and defaults are tested off. // Disable Android/iOS and enable macOS to make sure result is consistent and defaults are tested off.
FeatureFlags: () => TestFeatureFlags(isAndroidEnabled: false, isIOSEnabled: false, isMacOSEnabled: true), FeatureFlags: () => TestFeatureFlags(
isAndroidEnabled: false,
isIOSEnabled: false,
isMacOSEnabled: true,
isPreviewDeviceEnabled: true,
isWindowsEnabled: true,
),
}); });
testUsingContext('printError should send daemon.logMessage event', () async { testUsingContext('printError should send daemon.logMessage event', () async {
...@@ -342,18 +427,75 @@ void main() { ...@@ -342,18 +427,75 @@ void main() {
final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery();
daemon.deviceDomain.addDeviceDiscoverer(discoverer); daemon.deviceDomain.addDeviceDiscoverer(discoverer);
discoverer.addDevice(FakeAndroidDevice()); discoverer.addDevice(FakeAndroidDevice());
final MemoryFileSystem fs = MemoryFileSystem.test();
return daemonStreams.outputs.stream.skipWhile(_isConnectedEvent).first.then<void>((DaemonMessage response) async { discoverer.addDevice(PreviewDevice(
processManager: FakeProcessManager.empty(),
logger: BufferLogger.test(),
fileSystem: fs,
previewBinary: fs.file(r'preview_device.exe'),
artifacts: Artifacts.test(fileSystem: fs),
builderFactory: () => throw UnimplementedError('TODO implement builder factory'),
));
final List<Map<String, Object?>> names = <Map<String, Object?>>[];
await daemonStreams.outputs.stream.skipWhile(_isConnectedEvent).take(2).forEach((DaemonMessage response) async {
expect(response.data['event'], 'device.added'); expect(response.data['event'], 'device.added');
expect(response.data['params'], isMap); expect(response.data['params'], isMap);
final Map<String, Object?> params = castStringKeyedMap(response.data['params'])!; final Map<String, Object?> params = castStringKeyedMap(response.data['params'])!;
expect(params['platform'], isNotEmpty); // the fake device has a platform of 'android-arm' names.add(params);
}); });
await daemonStreams.outputs.close();
expect(
names,
containsAll(const <Map<String, Object?>>[
<String, Object?>{
'id': 'device',
'name': 'android device',
'platform': 'android-arm',
'emulator': false,
'category': 'mobile',
'platformType': 'android',
'ephemeral': false,
'emulatorId': 'device',
'sdk': 'Android 12',
'capabilities': <String, Object?>{
'hotReload': true,
'hotRestart': true,
'screenshot': true,
'fastStart': true,
'flutterExit': true,
'hardwareRendering': true,
'startPaused': true,
},
},
<String, Object?>{
'id': 'preview',
'name': 'Preview',
'platform': 'windows-x64',
'emulator': false,
'category': 'desktop',
'platformType': 'windowsPreview',
'ephemeral': false,
'emulatorId': null,
'sdk': 'preview',
'capabilities': <String, Object?>{
'hotReload': true,
'hotRestart': true,
'screenshot': false,
'fastStart': false,
'flutterExit': true,
'hardwareRendering': true,
'startPaused': true,
},
},
]),
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
AndroidWorkflow: () => FakeAndroidWorkflow(), AndroidWorkflow: () => FakeAndroidWorkflow(),
IOSWorkflow: () => FakeIOSWorkflow(), IOSWorkflow: () => FakeIOSWorkflow(),
FuchsiaWorkflow: () => FakeFuchsiaWorkflow(), FuchsiaWorkflow: () => FakeFuchsiaWorkflow(),
WindowsWorkflow: () => FakeWindowsWorkflow(),
}); });
testUsingContext('device.discoverDevices should respond with list', () async { testUsingContext('device.discoverDevices should respond with list', () async {
...@@ -930,6 +1072,13 @@ bool _notEvent(DaemonMessage message) => message.data['event'] == null; ...@@ -930,6 +1072,13 @@ bool _notEvent(DaemonMessage message) => message.data['event'] == null;
bool _isConnectedEvent(DaemonMessage message) => message.data['event'] == 'daemon.connected'; bool _isConnectedEvent(DaemonMessage message) => message.data['event'] == 'daemon.connected';
class FakeWindowsWorkflow extends Fake implements WindowsWorkflow {
FakeWindowsWorkflow({ this.canListDevices = true });
@override
final bool canListDevices;
}
class FakeFuchsiaWorkflow extends Fake implements FuchsiaWorkflow { class FakeFuchsiaWorkflow extends Fake implements FuchsiaWorkflow {
FakeFuchsiaWorkflow({ this.canListDevices = true }); FakeFuchsiaWorkflow({ this.canListDevices = true });
...@@ -956,7 +1105,7 @@ class FakeAndroidDevice extends Fake implements AndroidDevice { ...@@ -956,7 +1105,7 @@ class FakeAndroidDevice extends Fake implements AndroidDevice {
final String id = 'device'; final String id = 'device';
@override @override
final String name = 'device'; final String name = 'android device';
@override @override
Future<String> get emulatorId async => 'device'; Future<String> get emulatorId async => 'device';
......
...@@ -52,7 +52,7 @@ void main() { ...@@ -52,7 +52,7 @@ void main() {
); );
expect(await device.isLocalEmulator, false); expect(await device.isLocalEmulator, false);
expect(device.name, 'preview'); expect(device.name, 'Preview');
expect(await device.sdkNameAndVersion, 'preview'); expect(await device.sdkNameAndVersion, 'preview');
expect(await device.targetPlatform, TargetPlatform.windows_x64); expect(await device.targetPlatform, TargetPlatform.windows_x64);
expect(device.category, Category.desktop); expect(device.category, Category.desktop);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment