From ee42a302ec1d553d09a3239a7c1538cb2f79373e Mon Sep 17 00:00:00 2001 From: Victoria Ashworth Date: Mon, 13 Mar 2023 11:14:21 -0500 Subject: [PATCH] Move target devices logic to its own classes and file (#121903) Move target devices logic to its own classes and file --- .../lib/src/commands/devices.dart | 21 +- packages/flutter_tools/lib/src/device.dart | 88 +--- .../lib/src/runner/flutter_command.dart | 113 +---- .../lib/src/runner/target_devices.dart | 182 +++++++ .../commands.shard/hermetic/drive_test.dart | 19 - .../test/general.shard/device_test.dart | 182 +++---- .../runner/flutter_command_test.dart | 172 +------ .../runner/target_devices_test.dart | 476 ++++++++++++++++++ packages/flutter_tools/test/src/context.dart | 16 +- 9 files changed, 814 insertions(+), 455 deletions(-) create mode 100644 packages/flutter_tools/lib/src/runner/target_devices.dart create mode 100644 packages/flutter_tools/test/general.shard/runner/target_devices_test.dart diff --git a/packages/flutter_tools/lib/src/commands/devices.dart b/packages/flutter_tools/lib/src/commands/devices.dart index c7ceff1ed1..8d1adf7513 100644 --- a/packages/flutter_tools/lib/src/commands/devices.dart +++ b/packages/flutter_tools/lib/src/commands/devices.dart @@ -62,9 +62,27 @@ class DevicesCommand extends FlutterCommand { exitCode: 1); } + final DevicesCommandOutput output = DevicesCommandOutput( + deviceDiscoveryTimeout: deviceDiscoveryTimeout, + ); + + await output.findAndOutputAllTargetDevices( + machine: boolArgDeprecated('machine'), + ); + + return FlutterCommandResult.success(); + } +} + +class DevicesCommandOutput { + DevicesCommandOutput({this.deviceDiscoveryTimeout}); + + final Duration? deviceDiscoveryTimeout; + + Future findAndOutputAllTargetDevices({required bool machine}) async { final List devices = await globals.deviceManager?.refreshAllDevices(timeout: deviceDiscoveryTimeout) ?? []; - if (boolArgDeprecated('machine')) { + if (machine) { await printDevicesAsJson(devices); } else { if (devices.isEmpty) { @@ -86,7 +104,6 @@ class DevicesCommand extends FlutterCommand { } await _printDiagnostics(); } - return FlutterCommandResult.success(); } Future _printDiagnostics() async { diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index 484f447fbd..52c75af8ff 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -245,76 +245,11 @@ abstract class DeviceManager { ]; } - /// Find and return all target [Device]s based upon currently connected - /// devices, the current project, and criteria entered by the user on - /// the command line. - /// - /// If no device can be found that meets specified criteria, - /// then print an error message and return null. - /// - /// Returns a list of devices specified by the user. - /// - /// * If the user specified '-d all', then return all connected devices which - /// support the current project, except for fuchsia and web. - /// - /// * If the user specified a device id, then do nothing as the list is already - /// filtered by [getDevices]. - /// - /// * If the user did not specify a device id and there is more than one - /// device connected, then filter out unsupported devices and prioritize - /// ephemeral devices. - /// - /// * If [promptUserToChooseDevice] is true, and there are more than one - /// device after the aforementioned filters, and the user is connected to a - /// terminal, then show a prompt asking the user to choose one. - Future> findTargetDevices({ - bool includeDevicesUnsupportedByProject = false, - Duration? timeout, - }) async { - if (timeout != null) { - // Reset the cache with the specified timeout. - await refreshAllDevices(timeout: timeout); - } - - final List devices = await getDevices( - filter: DeviceDiscoveryFilter( - supportFilter: deviceSupportFilter( - includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject, - ), - ), - ); - - if (!hasSpecifiedDeviceId) { - // User did not specify the device. - - if (devices.length > 1) { - // If there are still multiple devices and the user did not specify to run - // all, then attempt to prioritize ephemeral devices. For example, if the - // user only typed 'flutter run' and both an Android device and desktop - // device are available, choose the Android device. - - // Ephemeral is nullable for device types where this is not well - // defined. - final List ephemeralDevices = [ - for (final Device device in devices) - if (device.ephemeral == true) - device, - ]; - - if (ephemeralDevices.length == 1) { - return ephemeralDevices; - } - } - } - - return devices; - } - /// Determines how to filter devices. /// /// By default, filters to only include devices that are supported by Flutter. /// - /// If the user has not specificied a device, filters to only include devices + /// If the user has not specified a device, filters to only include devices /// that are supported by Flutter and supported by the project. /// /// If the user has specified `--device all`, filters to only include devices @@ -343,6 +278,27 @@ abstract class DeviceManager { return DeviceDiscoverySupportFilter.excludeDevicesUnsupportedByFlutter(); } } + + /// If the user did not specify to run all or a specific device, then attempt + /// to prioritize ephemeral devices. + /// + /// If there is not exactly one ephemeral device return null. + /// + /// For example, if the user only typed 'flutter run' and both an Android + /// device and desktop device are available, choose the Android device. + /// + /// Note: ephemeral is nullable for device types where this is not well + /// defined. + Device? getSingleEphemeralDevice(List devices){ + if (!hasSpecifiedDeviceId) { + try { + return devices.singleWhere((Device device) => device.ephemeral == true); + } on StateError { + return null; + } + } + return null; + } } /// A class for determining how to filter devices based on if they are supported. diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 99e76ef526..ef8bb46485 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -31,6 +31,7 @@ import '../project.dart'; import '../reporting/reporting.dart'; import '../web/compile.dart'; import 'flutter_command_runner.dart'; +import 'target_devices.dart'; export '../cache.dart' show DevelopmentArtifact; @@ -709,6 +710,11 @@ abstract class FlutterCommand extends Command { return null; }(); + late final TargetDevices _targetDevices = TargetDevices( + deviceManager: globals.deviceManager!, + logger: globals.logger, + ); + void addBuildModeFlags({ required bool verboseHelp, bool defaultToRelease = true, @@ -1530,113 +1536,10 @@ abstract class FlutterCommand extends Command { Future?> findAllTargetDevices({ bool includeDevicesUnsupportedByProject = false, }) async { - if (!globals.doctor!.canLaunchAnything) { - globals.printError(userMessages.flutterNoDevelopmentDevice); - return null; - } - final DeviceManager deviceManager = globals.deviceManager!; - List devices = await deviceManager.findTargetDevices( + return _targetDevices.findAllTargetDevices( + deviceDiscoveryTimeout: deviceDiscoveryTimeout, includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject, - timeout: deviceDiscoveryTimeout, ); - - if (devices.isEmpty) { - if (deviceManager.hasSpecifiedDeviceId) { - globals.logger.printStatus(userMessages.flutterNoMatchingDevice(deviceManager.specifiedDeviceId!)); - final List allDevices = await deviceManager.getAllDevices(); - if (allDevices.isNotEmpty) { - globals.logger.printStatus(''); - globals.logger.printStatus('The following devices were found:'); - await Device.printDevices(allDevices, globals.logger); - } - return null; - } else if (deviceManager.hasSpecifiedAllDevices) { - globals.logger.printStatus(userMessages.flutterNoDevicesFound); - await _printUnsupportedDevice(deviceManager); - return null; - } else { - globals.logger.printStatus(userMessages.flutterNoSupportedDevices); - await _printUnsupportedDevice(deviceManager); - return null; - } - } else if (devices.length > 1) { - if (deviceManager.hasSpecifiedDeviceId) { - globals.logger.printStatus(userMessages.flutterFoundSpecifiedDevices(devices.length, deviceManager.specifiedDeviceId!)); - return null; - } else if (!deviceManager.hasSpecifiedAllDevices) { - if (globals.terminal.stdinHasTerminal) { - // If DeviceManager was not able to prioritize a device. For example, if the user - // has two active Android devices running, then we request the user to - // choose one. If the user has two nonEphemeral devices running, we also - // request input to choose one. - globals.logger.printStatus(userMessages.flutterMultipleDevicesFound); - await Device.printDevices(devices, globals.logger); - final Device chosenDevice = await _chooseOneOfAvailableDevices(devices); - - // Update the [DeviceManager.specifiedDeviceId] so that we will not be prompted again. - deviceManager.specifiedDeviceId = chosenDevice.id; - - devices = [chosenDevice]; - } else { - // Show an error message asking the user to specify `-d all` if they - // want to run on multiple devices. - final List allDevices = await deviceManager.getAllDevices(); - globals.logger.printStatus(userMessages.flutterSpecifyDeviceWithAllOption); - globals.logger.printStatus(''); - await Device.printDevices(allDevices, globals.logger); - return null; - } - } - } - - return devices; - } - - Future _printUnsupportedDevice(DeviceManager deviceManager) async { - final List unsupportedDevices = await deviceManager.getDevices(); - if (unsupportedDevices.isNotEmpty) { - final StringBuffer result = StringBuffer(); - result.writeln(userMessages.flutterFoundButUnsupportedDevices); - result.writeAll( - (await Device.descriptions(unsupportedDevices)) - .map((String desc) => desc) - .toList(), - '\n', - ); - result.writeln(); - result.writeln(userMessages.flutterMissPlatformProjects( - Device.devicesPlatformTypes(unsupportedDevices), - )); - globals.logger.printStatus(result.toString()); - } - } - - Future _chooseOneOfAvailableDevices(List devices) async { - _displayDeviceOptions(devices); - final String userInput = await _readUserInput(devices.length); - if (userInput.toLowerCase() == 'q') { - throwToolExit(''); - } - return devices[int.parse(userInput) - 1]; - } - - void _displayDeviceOptions(List devices) { - int count = 1; - for (final Device device in devices) { - globals.logger.printStatus(userMessages.flutterChooseDevice(count, device.name, device.id)); - count++; - } - } - - Future _readUserInput(int deviceCount) async { - globals.terminal.usesTerminalUi = true; - final String result = await globals.terminal.promptForCharInput( - [ for (int i = 0; i < deviceCount; i++) '${i + 1}', 'q', 'Q'], - displayAcceptedCharacters: false, - logger: globals.logger, - prompt: userMessages.flutterChooseOne, - ); - return result; } /// Find and return the target [Device] based upon currently connected diff --git a/packages/flutter_tools/lib/src/runner/target_devices.dart b/packages/flutter_tools/lib/src/runner/target_devices.dart new file mode 100644 index 0000000000..6f1ae09f0c --- /dev/null +++ b/packages/flutter_tools/lib/src/runner/target_devices.dart @@ -0,0 +1,182 @@ +// 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. + +import 'package:meta/meta.dart'; + +import '../base/common.dart'; +import '../base/logger.dart'; +import '../base/user_messages.dart'; +import '../device.dart'; +import '../globals.dart' as globals; + +class TargetDevices { + TargetDevices({ + required DeviceManager deviceManager, + required Logger logger, + }) : _deviceManager = deviceManager, + _logger = logger; + + final DeviceManager _deviceManager; + final Logger _logger; + + /// Find and return all target [Device]s based upon currently connected + /// devices and criteria entered by the user on the command line. + /// If no device can be found that meets specified criteria, + /// then print an error message and return null. + Future?> findAllTargetDevices({ + Duration? deviceDiscoveryTimeout, + bool includeDevicesUnsupportedByProject = false, + }) async { + if (!globals.doctor!.canLaunchAnything) { + _logger.printError(userMessages.flutterNoDevelopmentDevice); + return null; + } + List devices = await getDevices( + includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject, + timeout: deviceDiscoveryTimeout, + ); + + if (devices.isEmpty) { + if (_deviceManager.hasSpecifiedDeviceId) { + _logger.printStatus(userMessages.flutterNoMatchingDevice(_deviceManager.specifiedDeviceId!)); + final List allDevices = await _deviceManager.getAllDevices(); + if (allDevices.isNotEmpty) { + _logger.printStatus(''); + _logger.printStatus('The following devices were found:'); + await Device.printDevices(allDevices, _logger); + } + return null; + } else if (_deviceManager.hasSpecifiedAllDevices) { + _logger.printStatus(userMessages.flutterNoDevicesFound); + await _printUnsupportedDevice(_deviceManager); + return null; + } else { + _logger.printStatus(userMessages.flutterNoSupportedDevices); + await _printUnsupportedDevice(_deviceManager); + return null; + } + } else if (devices.length > 1) { + if (_deviceManager.hasSpecifiedDeviceId) { + _logger.printStatus(userMessages.flutterFoundSpecifiedDevices(devices.length, _deviceManager.specifiedDeviceId!)); + return null; + } else if (!_deviceManager.hasSpecifiedAllDevices) { + if (globals.terminal.stdinHasTerminal) { + // If DeviceManager was not able to prioritize a device. For example, if the user + // has two active Android devices running, then we request the user to + // choose one. If the user has two nonEphemeral devices running, we also + // request input to choose one. + _logger.printStatus(userMessages.flutterMultipleDevicesFound); + await Device.printDevices(devices, _logger); + final Device chosenDevice = await _chooseOneOfAvailableDevices(devices); + + // Update the [DeviceManager.specifiedDeviceId] so that we will not be prompted again. + _deviceManager.specifiedDeviceId = chosenDevice.id; + + devices = [chosenDevice]; + } else { + // Show an error message asking the user to specify `-d all` if they + // want to run on multiple devices. + final List allDevices = await _deviceManager.getAllDevices(); + _logger.printStatus(userMessages.flutterSpecifyDeviceWithAllOption); + _logger.printStatus(''); + await Device.printDevices(allDevices, _logger); + return null; + } + } + } + + return devices; + } + + Future _printUnsupportedDevice(DeviceManager deviceManager) async { + final List unsupportedDevices = await deviceManager.getDevices(); + if (unsupportedDevices.isNotEmpty) { + final StringBuffer result = StringBuffer(); + result.writeln(userMessages.flutterFoundButUnsupportedDevices); + result.writeAll( + (await Device.descriptions(unsupportedDevices)) + .map((String desc) => desc) + .toList(), + '\n', + ); + result.writeln(); + result.writeln(userMessages.flutterMissPlatformProjects( + Device.devicesPlatformTypes(unsupportedDevices), + )); + _logger.printStatus(result.toString()); + } + } + + Future _chooseOneOfAvailableDevices(List devices) async { + _displayDeviceOptions(devices); + final String userInput = await _readUserInput(devices.length); + if (userInput.toLowerCase() == 'q') { + throwToolExit(''); + } + return devices[int.parse(userInput) - 1]; + } + + void _displayDeviceOptions(List devices) { + int count = 1; + for (final Device device in devices) { + _logger.printStatus(userMessages.flutterChooseDevice(count, device.name, device.id)); + count++; + } + } + + Future _readUserInput(int deviceCount) async { + globals.terminal.usesTerminalUi = true; + final String result = await globals.terminal.promptForCharInput( + [ for (int i = 0; i < deviceCount; i++) '${i + 1}', 'q', 'Q'], + displayAcceptedCharacters: false, + logger: _logger, + prompt: userMessages.flutterChooseOne, + ); + return result; + } + + /// Find and return all target [Device]s based upon currently connected + /// devices, the current project, and criteria entered by the user on + /// the command line. + /// + /// Returns a list of devices specified by the user. + /// + /// * If the user specified '-d all', then return all connected devices which + /// support the current project, except for fuchsia and web. + /// + /// * If the user specified a device id, then do nothing as the list is already + /// filtered by [_deviceManager.getDevices]. + /// + /// * If the user did not specify a device id and there is more than one + /// device connected, then filter out unsupported devices and prioritize + /// ephemeral devices. + @visibleForTesting + Future> getDevices({ + bool includeDevicesUnsupportedByProject = false, + Duration? timeout, + }) async { + if (timeout != null) { + // Reset the cache with the specified timeout. + await _deviceManager.refreshAllDevices(timeout: timeout); + } + + final List devices = await _deviceManager.getDevices( + filter: DeviceDiscoveryFilter( + supportFilter: _deviceManager.deviceSupportFilter( + includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject, + ), + ), + ); + + // If there is more than one device, attempt to prioritize ephemeral devices. + if (devices.length > 1) { + final Device? ephemeralDevice = _deviceManager.getSingleEphemeralDevice(devices); + if (ephemeralDevice != null) { + return [ephemeralDevice]; + } + } + + return devices; + } +} diff --git a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart index ade6283275..f3cebbe008 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart @@ -581,25 +581,6 @@ class FakePub extends Fake implements Pub { }) async { } } -class FakeDeviceManager extends Fake implements DeviceManager { - List devices = []; - - @override - String? specifiedDeviceId; - - @override - Future> getDevices({ - DeviceDiscoveryFilter? filter, - }) async => devices; - - @override - Future> findTargetDevices({ - bool includeDevicesUnsupportedByProject = false, - Duration? timeout, - bool promptUserToChooseDevice = true, - }) async => devices; -} - /// A [FlutterDriverFactory] that creates a [NeverEndingDriverService]. class NeverEndingFlutterDriverFactory extends Fake implements FlutterDriverFactory { NeverEndingFlutterDriverFactory(this.callback); diff --git a/packages/flutter_tools/test/general.shard/device_test.dart b/packages/flutter_tools/test/general.shard/device_test.dart index 757a3ecee3..0d0b08bc2b 100644 --- a/packages/flutter_tools/test/general.shard/device_test.dart +++ b/packages/flutter_tools/test/general.shard/device_test.dart @@ -205,22 +205,21 @@ void main() { ephemeralOne, nonEphemeralOne, nonEphemeralTwo, - unsupported, - unsupportedForProject, ]; final DeviceManager deviceManager = TestDeviceManager( devices, logger: BufferLogger.test(), ); - final List filtered = await deviceManager.findTargetDevices(); - expect(filtered.single, ephemeralOne); + final Device? ephemeralDevice = deviceManager.getSingleEphemeralDevice(devices); + + expect(ephemeralDevice, ephemeralOne); }, overrides: { FlutterProject: () => FakeFlutterProject(), }); - testUsingContext('returns all devices when multiple non ephemeral devices are found', () async { + testUsingContext('returns null when multiple non ephemeral devices are found', () async { final List devices = [ ephemeralOne, ephemeralTwo, @@ -233,19 +232,52 @@ void main() { logger: BufferLogger.test(), ); - final List filtered = await deviceManager.findTargetDevices(); + final Device? ephemeralDevice = deviceManager.getSingleEphemeralDevice(devices); - expect(filtered, [ - ephemeralOne, - ephemeralTwo, - nonEphemeralOne, - nonEphemeralTwo, - ]); + expect(ephemeralDevice, isNull); }, overrides: { FlutterProject: () => FakeFlutterProject(), }); - testUsingContext('Unsupported devices listed in all devices', () async { + testUsingContext('return null when hasSpecifiedDeviceId is true', () async { + final List devices = [ + ephemeralOne, + nonEphemeralOne, + nonEphemeralTwo, + ]; + + final DeviceManager deviceManager = TestDeviceManager( + devices, + logger: BufferLogger.test(), + ); + deviceManager.specifiedDeviceId = 'device'; + + final Device? ephemeralDevice = deviceManager.getSingleEphemeralDevice(devices); + + expect(ephemeralDevice, isNull); + }, overrides: { + FlutterProject: () => FakeFlutterProject(), + }); + + testUsingContext('returns null when no ephemeral devices are found', () async { + final List devices = [ + nonEphemeralOne, + nonEphemeralTwo, + ]; + + final DeviceManager deviceManager = TestDeviceManager( + devices, + logger: BufferLogger.test(), + ); + + final Device? ephemeralDevice = deviceManager.getSingleEphemeralDevice(devices); + + expect(ephemeralDevice, isNull); + }, overrides: { + FlutterProject: () => FakeFlutterProject(), + }); + + testWithoutContext('Unsupported devices listed in all devices', () async { final List devices = [ unsupported, unsupportedForProject, @@ -255,14 +287,12 @@ void main() { devices, logger: BufferLogger.test(), ); - final List filtered = await deviceManager.getAllDevices(); + final List filtered = await deviceManager.getDevices(); expect(filtered, [ unsupported, unsupportedForProject, ]); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testUsingContext('Removes unsupported devices', () async { @@ -274,14 +304,16 @@ void main() { devices, logger: BufferLogger.test(), ); - final List filtered = await deviceManager.findTargetDevices(); + final List filtered = await deviceManager.getDevices( + filter: DeviceDiscoveryFilter( + supportFilter: deviceManager.deviceSupportFilter(), + ), + ); expect(filtered, []); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); - testUsingContext('Retains devices unsupported by the project if FlutterProject is null', () async { + testUsingContext('Retains devices unsupported by the project if includeDevicesUnsupportedByProject is true', () async { final List devices = [ unsupported, unsupportedForProject, @@ -291,13 +323,15 @@ void main() { devices, logger: BufferLogger.test(), ); - final List filtered = await deviceManager.findTargetDevices( - includeDevicesUnsupportedByProject: true, + final List filtered = await deviceManager.getDevices( + filter: DeviceDiscoveryFilter( + supportFilter: deviceManager.deviceSupportFilter( + includeDevicesUnsupportedByProject: true, + ), + ), ); expect(filtered, [unsupportedForProject]); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testUsingContext('Removes web and fuchsia from --all', () async { @@ -311,13 +345,13 @@ void main() { ); deviceManager.specifiedDeviceId = 'all'; - final List filtered = await deviceManager.findTargetDevices( - includeDevicesUnsupportedByProject: true, + final List filtered = await deviceManager.getDevices( + filter: DeviceDiscoveryFilter( + supportFilter: deviceManager.deviceSupportFilter(), + ), ); expect(filtered, []); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testUsingContext('Removes devices unsupported by the project from --all', () async { @@ -333,19 +367,22 @@ void main() { ); deviceManager.specifiedDeviceId = 'all'; - final List filtered = await deviceManager.findTargetDevices(); + final List filtered = await deviceManager.getDevices( + filter: DeviceDiscoveryFilter( + supportFilter: deviceManager.deviceSupportFilter(), + ), + ); expect(filtered, [ nonEphemeralOne, nonEphemeralTwo, ]); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testUsingContext('Returns device with the specified id', () async { final List devices = [ nonEphemeralOne, + nonEphemeralTwo, ]; final DeviceManager deviceManager = TestDeviceManager( devices, @@ -353,13 +390,15 @@ void main() { ); deviceManager.specifiedDeviceId = nonEphemeralOne.id; - final List filtered = await deviceManager.findTargetDevices(); + final List filtered = await deviceManager.getDevices( + filter: DeviceDiscoveryFilter( + supportFilter: deviceManager.deviceSupportFilter(), + ), + ); expect(filtered, [ nonEphemeralOne, ]); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testUsingContext('Returns multiple devices when multiple devices matches the specified id', () async { @@ -373,14 +412,16 @@ void main() { ); deviceManager.specifiedDeviceId = 'nonEphemeral'; // This prefix matches both devices - final List filtered = await deviceManager.findTargetDevices(); + final List filtered = await deviceManager.getDevices( + filter: DeviceDiscoveryFilter( + supportFilter: deviceManager.deviceSupportFilter(), + ), + ); expect(filtered, [ nonEphemeralOne, nonEphemeralTwo, ]); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testUsingContext('Returns empty when device of specified id is not found', () async { @@ -393,11 +434,13 @@ void main() { ); deviceManager.specifiedDeviceId = nonEphemeralTwo.id; - final List filtered = await deviceManager.findTargetDevices(); + final List filtered = await deviceManager.getDevices( + filter: DeviceDiscoveryFilter( + supportFilter: deviceManager.deviceSupportFilter(), + ), + ); expect(filtered, []); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testWithoutContext('uses DeviceDiscoverySupportFilter.isDeviceSupportedForProject instead of device.isSupportedForProject', () async { @@ -439,8 +482,6 @@ void main() { final List filtered = await deviceManager.getDevices(); expect(filtered, []); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testUsingContext('Return unconnected devices when filter allows', () async { @@ -460,8 +501,6 @@ void main() { ); expect(filtered, [unconnectedDevice]); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testUsingContext('Filter to only include wireless devices', () async { @@ -482,8 +521,6 @@ void main() { ); expect(filtered, [wirelessDevice]); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); testUsingContext('Filter to only include attached devices', () async { @@ -504,59 +541,6 @@ void main() { ); expect(filtered, [ephemeralOne]); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), - }); - - testUsingContext('does not refresh device cache without a timeout', () async { - final List devices = [ - ephemeralOne, - ]; - final MockDeviceDiscovery deviceDiscovery = MockDeviceDiscovery() - ..deviceValues = devices; - - final DeviceManager deviceManager = TestDeviceManager( - [], - deviceDiscoveryOverrides: [ - deviceDiscovery, - ], - logger: BufferLogger.test(), - ); - deviceManager.specifiedDeviceId = ephemeralOne.id; - final List filtered = await deviceManager.findTargetDevices(); - - expect(filtered.single, ephemeralOne); - expect(deviceDiscovery.devicesCalled, 1); - expect(deviceDiscovery.discoverDevicesCalled, 0); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), - }); - - testUsingContext('refreshes device cache with a timeout', () async { - final List devices = [ - ephemeralOne, - ]; - const Duration timeout = Duration(seconds: 2); - final MockDeviceDiscovery deviceDiscovery = MockDeviceDiscovery() - ..deviceValues = devices; - - final DeviceManager deviceManager = TestDeviceManager( - [], - deviceDiscoveryOverrides: [ - deviceDiscovery, - ], - logger: BufferLogger.test(), - ); - deviceManager.specifiedDeviceId = ephemeralOne.id; - final List filtered = await deviceManager.findTargetDevices( - timeout: timeout, - ); - - expect(filtered.single, ephemeralOne); - expect(deviceDiscovery.devicesCalled, 1); - expect(deviceDiscovery.discoverDevicesCalled, 1); - }, overrides: { - FlutterProject: () => FakeFlutterProject(), }); }); diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart index 4b3b729cb2..06f833669f 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart @@ -11,9 +11,7 @@ import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/error_handling_io.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/signals.dart'; -import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/time.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/build_info.dart'; @@ -696,135 +694,31 @@ void main() { ProcessManager: () => processManager, }); - group('findAllTargetDevices', () { + group('findTargetDevice', () { final FakeDevice device1 = FakeDevice('device1', 'device1'); final FakeDevice device2 = FakeDevice('device2', 'device2'); - group('when specified device id', () { - testUsingContext('returns device when device is found', () async { - testDeviceManager.specifiedDeviceId = 'device-id'; - testDeviceManager.addDevice(device1); - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - expect(devices, [device1]); - }); - testUsingContext('show error when no device found', () async { - testDeviceManager.specifiedDeviceId = 'device-id'; - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - expect(devices, null); - expect(testLogger.statusText, contains(UserMessages().flutterNoMatchingDevice('device-id'))); - }); - - testUsingContext('show error when multiple devices found', () async { - testDeviceManager.specifiedDeviceId = 'device-id'; - testDeviceManager.addDevice(device1); - testDeviceManager.addDevice(device2); - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - expect(devices, null); - expect(testLogger.statusText, contains(UserMessages().flutterFoundSpecifiedDevices(2, 'device-id'))); - }); + testUsingContext('no device found', () async { + final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); + final Device? device = await flutterCommand.findTargetDevice(); + expect(device, isNull); }); - group('when specified all', () { - testUsingContext('can return one device', () async { - testDeviceManager.specifiedDeviceId = 'all'; - testDeviceManager.addDevice(device1); - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - expect(devices, [device1]); - }); - - testUsingContext('can return multiple devices', () async { - testDeviceManager.specifiedDeviceId = 'all'; - testDeviceManager.addDevice(device1); - testDeviceManager.addDevice(device2); - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - expect(devices, [device1, device2]); - }); - - testUsingContext('show error when no device found', () async { - testDeviceManager.specifiedDeviceId = 'all'; - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - expect(devices, null); - expect(testLogger.statusText, contains(UserMessages().flutterNoDevicesFound)); - }); + testUsingContext('finds single device', () async { + testDeviceManager.addDevice(device1); + final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); + final Device? device = await flutterCommand.findTargetDevice(); + expect(device, device1); }); - group('when device not specified', () { - testUsingContext('returns one device when only one device connected', () async { - testDeviceManager.addDevice(device1); - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - expect(devices, [device1]); - }); - - testUsingContext('show error when no device found', () async { - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - expect(devices, null); - expect(testLogger.statusText, contains(UserMessages().flutterNoSupportedDevices)); - }); - - testUsingContext('show error when multiple devices found and not connected to terminal', () async { - testDeviceManager.addDevice(device1); - testDeviceManager.addDevice(device2); - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - expect(devices, null); - expect(testLogger.statusText, contains(UserMessages().flutterSpecifyDeviceWithAllOption)); - }, overrides: { - AnsiTerminal: () => FakeTerminal(stdinHasTerminal: false), - }); - - // Prompt to choose device when multiple devices found and connected to terminal - group('show prompt', () { - late FakeTerminal terminal; - setUp(() { - terminal = FakeTerminal(); - }); - - testUsingContext('choose first device', () async { - testDeviceManager.addDevice(device1); - testDeviceManager.addDevice(device2); - terminal.setPrompt(['1', '2', 'q', 'Q'], '1'); - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - - expect(devices, [device1]); - }, overrides: { - AnsiTerminal: () => terminal, - }); - - testUsingContext('choose second device', () async { - testDeviceManager.addDevice(device1); - testDeviceManager.addDevice(device2); - terminal.setPrompt(['1', '2', 'q', 'Q'], '2'); - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - final List? devices = await flutterCommand.findAllTargetDevices(); - - expect(devices, [device2]); - }, overrides: { - AnsiTerminal: () => terminal, - }); - - testUsingContext('exits without choosing device', () async { - testDeviceManager.addDevice(device1); - testDeviceManager.addDevice(device2); - terminal.setPrompt(['1', '2', 'q', 'Q'], 'q'); - final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); - - await expectLater( - flutterCommand.findAllTargetDevices(), - throwsToolExit(), - ); - }, overrides: { - AnsiTerminal: () => terminal, - }); - }); + testUsingContext('finds multiple devices', () async { + testDeviceManager.addDevice(device1); + testDeviceManager.addDevice(device2); + testDeviceManager.specifiedDeviceId = 'all'; + final DummyFlutterCommand flutterCommand = DummyFlutterCommand(); + final Device? device = await flutterCommand.findTargetDevice(); + expect(device, isNull); + expect(testLogger.statusText, contains(UserMessages().flutterSpecifyDevice)); }); }); }); @@ -980,33 +874,3 @@ class FakePub extends Fake implements Pub { PubOutputMode outputMode = PubOutputMode.all, }) async { } } - -class FakeTerminal extends Fake implements AnsiTerminal { - FakeTerminal({this.stdinHasTerminal = true}); - - @override - final bool stdinHasTerminal; - - @override - bool usesTerminalUi = true; - - void setPrompt(List characters, String result) { - _nextPrompt = characters; - _nextResult = result; - } - - List? _nextPrompt; - late String _nextResult; - - @override - Future promptForCharInput( - List acceptedCharacters, { - Logger? logger, - String? prompt, - int? defaultChoiceIndex, - bool displayAcceptedCharacters = true, - }) async { - expect(acceptedCharacters, _nextPrompt); - return _nextResult; - } -} diff --git a/packages/flutter_tools/test/general.shard/runner/target_devices_test.dart b/packages/flutter_tools/test/general.shard/runner/target_devices_test.dart new file mode 100644 index 0000000000..12f90ff0f9 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/runner/target_devices_test.dart @@ -0,0 +1,476 @@ +// 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. + +import 'dart:async'; + +import 'package:flutter_tools/src/android/android_workflow.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; +import 'package:flutter_tools/src/base/user_messages.dart'; +import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/doctor.dart'; +import 'package:flutter_tools/src/doctor_validator.dart'; +import 'package:flutter_tools/src/runner/target_devices.dart'; +import 'package:test/fake.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/fake_devices.dart'; + +void main() { + group('When cannot launch anything', () { + late BufferLogger logger; + late FakeDoctor doctor; + final FakeDevice device1 = FakeDevice('device1', 'device1'); + + setUp(() { + logger = BufferLogger.test(); + doctor = FakeDoctor(logger, canLaunchAnything: false); + }); + + testUsingContext('does not search for devices', () async { + final MockDeviceDiscovery deviceDiscovery = MockDeviceDiscovery() + ..deviceValues = [device1]; + + final DeviceManager deviceManager = TestDeviceManager( + [], + deviceDiscoveryOverrides: [ + deviceDiscovery, + ], + logger: logger, + ); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: deviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(logger.errorText, contains(UserMessages().flutterNoDevelopmentDevice)); + expect(devices, isNull); + expect(deviceDiscovery.devicesCalled, 0); + expect(deviceDiscovery.discoverDevicesCalled, 0); + }, overrides: { + Doctor: () => doctor, + }); + }); + + group('Ensure refresh when deviceDiscoveryTimeout is provided', () { + late BufferLogger logger; + final FakeDevice device1 = FakeDevice('device1', 'device1'); + + setUp(() { + logger = BufferLogger.test(); + }); + + testUsingContext('does not refresh device cache without a timeout', () async { + final MockDeviceDiscovery deviceDiscovery = MockDeviceDiscovery() + ..deviceValues = [device1]; + + final DeviceManager deviceManager = TestDeviceManager( + [], + deviceDiscoveryOverrides: [ + deviceDiscovery, + ], + logger: logger, + ); + deviceManager.specifiedDeviceId = device1.id; + + final TargetDevices targetDevices = TargetDevices( + deviceManager: deviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices?.single, device1); + expect(deviceDiscovery.devicesCalled, 1); + expect(deviceDiscovery.discoverDevicesCalled, 0); + }); + + testUsingContext('refreshes device cache with a timeout', () async { + final MockDeviceDiscovery deviceDiscovery = MockDeviceDiscovery() + ..deviceValues = [device1]; + + final DeviceManager deviceManager = TestDeviceManager( + [], + deviceDiscoveryOverrides: [ + deviceDiscovery, + ], + logger: BufferLogger.test(), + ); + deviceManager.specifiedDeviceId = device1.id; + + const Duration timeout = Duration(seconds: 2); + final TargetDevices targetDevices = TargetDevices( + deviceManager: deviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices( + deviceDiscoveryTimeout: timeout, + ); + + expect(devices?.single, device1); + expect(deviceDiscovery.devicesCalled, 1); + expect(deviceDiscovery.discoverDevicesCalled, 1); + }); + }); + + group('findAllTargetDevices', () { + late BufferLogger logger; + final FakeDevice device1 = FakeDevice('device1', 'device1'); + final FakeDevice device2 = FakeDevice('device2', 'device2'); + + setUp(() { + logger = BufferLogger.test(); + }); + + group('when specified device id', () { + testUsingContext('returns device when device is found', () async { + testDeviceManager.specifiedDeviceId = 'device1'; + testDeviceManager.addDevice(device1); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, [device1]); + }); + + testUsingContext('show error when no device found', () async { + testDeviceManager.specifiedDeviceId = 'device-id'; + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, null); + expect(logger.statusText, contains(UserMessages().flutterNoMatchingDevice('device-id'))); + }); + + testUsingContext('show error when multiple devices found', () async { + testDeviceManager.specifiedDeviceId = 'device'; + testDeviceManager.addDevice(device1); + testDeviceManager.addDevice(device2); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, null); + expect(logger.statusText, contains(UserMessages().flutterFoundSpecifiedDevices(2, 'device'))); + }); + }); + + group('when specified all', () { + testUsingContext('can return one device', () async { + testDeviceManager.specifiedDeviceId = 'all'; + testDeviceManager.addDevice(device1); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, [device1]); + }); + + testUsingContext('can return multiple devices', () async { + testDeviceManager.specifiedDeviceId = 'all'; + testDeviceManager.addDevice(device1); + testDeviceManager.addDevice(device2); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, [device1, device2]); + }); + + testUsingContext('show error when no device found', () async { + testDeviceManager.specifiedDeviceId = 'all'; + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, null); + expect(logger.statusText, contains(UserMessages().flutterNoDevicesFound)); + }); + }); + + group('when device not specified', () { + testUsingContext('returns one device when only one device connected', () async { + testDeviceManager.addDevice(device1); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, [device1]); + }); + + testUsingContext('show error when no device found', () async { + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, null); + expect(logger.statusText, contains(UserMessages().flutterNoSupportedDevices)); + }); + + testUsingContext('show error when multiple devices found and not connected to terminal', () async { + testDeviceManager.addDevice(device1); + testDeviceManager.addDevice(device2); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, null); + expect(logger.statusText, contains(UserMessages().flutterSpecifyDeviceWithAllOption)); + }, overrides: { + AnsiTerminal: () => FakeTerminal(stdinHasTerminal: false), + }); + + // Prompt to choose device when multiple devices found and connected to terminal + group('show prompt', () { + late FakeTerminal terminal; + setUp(() { + terminal = FakeTerminal(); + }); + + testUsingContext('choose first device', () async { + testDeviceManager.addDevice(device1); + testDeviceManager.addDevice(device2); + terminal.setPrompt(['1', '2', 'q', 'Q'], '1'); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, [device1]); + }, overrides: { + AnsiTerminal: () => terminal, + }); + + testUsingContext('choose second device', () async { + testDeviceManager.addDevice(device1); + testDeviceManager.addDevice(device2); + terminal.setPrompt(['1', '2', 'q', 'Q'], '2'); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + final List? devices = await targetDevices.findAllTargetDevices(); + + expect(devices, [device2]); + }, overrides: { + AnsiTerminal: () => terminal, + }); + + testUsingContext('exits without choosing device', () async { + testDeviceManager.addDevice(device1); + testDeviceManager.addDevice(device2); + terminal.setPrompt(['1', '2', 'q', 'Q'], 'q'); + + final TargetDevices targetDevices = TargetDevices( + deviceManager: testDeviceManager, + logger: logger, + ); + + await expectLater( + targetDevices.findAllTargetDevices(), + throwsToolExit(), + ); + }, overrides: { + AnsiTerminal: () => terminal, + }); + }); + }); + }); + + group('Filter devices', () { + late BufferLogger logger; + final FakeDevice ephemeralOne = FakeDevice('ephemeralOne', 'ephemeralOne'); + final FakeDevice ephemeralTwo = FakeDevice('ephemeralTwo', 'ephemeralTwo'); + final FakeDevice nonEphemeralOne = FakeDevice('nonEphemeralOne', 'nonEphemeralOne', ephemeral: false); + + setUp(() { + logger = BufferLogger.test(); + }); + + testUsingContext('chooses ephemeral device', () async { + final List devices = [ + ephemeralOne, + nonEphemeralOne, + ]; + final DeviceManager deviceManager = TestDeviceManager( + devices, + logger: logger, + ); + + final TargetDevices targetDevices = TargetDevices(deviceManager: deviceManager, logger: logger); + final List filtered = await targetDevices.getDevices(); + + expect(filtered, [ephemeralOne]); + }); + + testUsingContext('returns all devices when multiple non ephemeral devices are found', () async { + final List devices = [ + ephemeralOne, + ephemeralTwo, + nonEphemeralOne, + ]; + final DeviceManager deviceManager = TestDeviceManager( + devices, + logger: logger, + ); + + final TargetDevices targetDevices = TargetDevices(deviceManager: deviceManager, logger: logger); + final List filtered = await targetDevices.getDevices(); + + expect(filtered, [ + ephemeralOne, + ephemeralTwo, + nonEphemeralOne, + ]); + }); + }); +} + +class TestDeviceManager extends DeviceManager { + TestDeviceManager( + List allDevices, { + List? deviceDiscoveryOverrides, + required super.logger, + String? wellKnownId, + FakePollingDeviceDiscovery? fakeDiscoverer, + }) : _fakeDeviceDiscoverer = fakeDiscoverer ?? FakePollingDeviceDiscovery(), + _deviceDiscoverers = [], + super() { + if (wellKnownId != null) { + _fakeDeviceDiscoverer.wellKnownIds.add(wellKnownId); + } + _deviceDiscoverers.add(_fakeDeviceDiscoverer); + if (deviceDiscoveryOverrides != null) { + _deviceDiscoverers.addAll(deviceDiscoveryOverrides); + } + resetDevices(allDevices); + } + @override + List get deviceDiscoverers => _deviceDiscoverers; + final List _deviceDiscoverers; + final FakePollingDeviceDiscovery _fakeDeviceDiscoverer; + + void resetDevices(List allDevices) { + _fakeDeviceDiscoverer.setDevices(allDevices); + } +} + +class MockDeviceDiscovery extends Fake implements DeviceDiscovery { + int devicesCalled = 0; + int discoverDevicesCalled = 0; + + @override + bool supportsPlatform = true; + + List deviceValues = []; + + @override + Future> devices({DeviceDiscoveryFilter? filter}) async { + devicesCalled += 1; + return deviceValues; + } + + @override + Future> discoverDevices({ + Duration? timeout, + DeviceDiscoveryFilter? filter, + }) async { + discoverDevicesCalled += 1; + return deviceValues; + } + + @override + List get wellKnownIds => []; +} + +class FakeTerminal extends Fake implements AnsiTerminal { + FakeTerminal({this.stdinHasTerminal = true}); + + @override + final bool stdinHasTerminal; + + @override + bool usesTerminalUi = true; + + void setPrompt(List characters, String result) { + _nextPrompt = characters; + _nextResult = result; + } + + List? _nextPrompt; + late String _nextResult; + + @override + Future promptForCharInput( + List acceptedCharacters, { + Logger? logger, + String? prompt, + int? defaultChoiceIndex, + bool displayAcceptedCharacters = true, + }) async { + expect(acceptedCharacters, _nextPrompt); + return _nextResult; + } +} + +class FakeDoctor extends Doctor { + FakeDoctor( + Logger logger, { + this.canLaunchAnything = true, + }) : super(logger: logger); + + // True for testing. + @override + bool get canListAnything => true; + + // True for testing. + @override + bool canLaunchAnything; + + @override + /// Replaces the android workflow with a version that overrides licensesAccepted, + /// to prevent individual tests from having to mock out the process for + /// the Doctor. + List get validators { + final List superValidators = super.validators; + return superValidators.map((DoctorValidator v) { + if (v is AndroidLicenseValidator) { + return FakeAndroidLicenseValidator(); + } + return v; + }).toList(); + } +} diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart index d2d94fa6d8..9b8aff7f10 100644 --- a/packages/flutter_tools/test/src/context.dart +++ b/packages/flutter_tools/test/src/context.dart @@ -222,7 +222,9 @@ class FakeDeviceManager implements DeviceManager { String deviceId, { DeviceDiscoveryFilter? filter, }) async { - return devices.where((Device device) => device.id == deviceId).toList(); + return devices.where((Device device) { + return device.id == deviceId || device.id.startsWith(deviceId); + }).toList(); } @override @@ -245,15 +247,6 @@ class FakeDeviceManager implements DeviceManager { @override List get deviceDiscoverers => []; - @override - Future> findTargetDevices({ - bool includeDevicesUnsupportedByProject = false, - Duration? timeout, - bool promptUserToChooseDevice = true, - }) async { - return devices; - } - @override DeviceDiscoverySupportFilter deviceSupportFilter({ bool includeDevicesUnsupportedByProject = false, @@ -261,6 +254,9 @@ class FakeDeviceManager implements DeviceManager { }) { return TestDeviceDiscoverySupportFilter(); } + + @override + Device? getSingleEphemeralDevice(List devices) => null; } class TestDeviceDiscoverySupportFilter extends Fake implements DeviceDiscoverySupportFilter {