Add '-t' option to 'attach' command. (#20539)
* Add '-t' option to 'attach' command.
* Add test
* Make analyzer happy
* Fix tests so they use memory file system and can find lib/main.dart
diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart
index cd550f6..2812b4c 100644
--- a/packages/flutter_tools/lib/src/commands/attach.dart
+++ b/packages/flutter_tools/lib/src/commands/attach.dart
@@ -35,7 +35,7 @@
/// As soon as a new observatory is detected the command attaches to it and
/// enables hot reloading.
class AttachCommand extends FlutterCommand {
- AttachCommand({bool verboseHelp = false}) {
+ AttachCommand({bool verboseHelp = false, this.hotRunnerFactory}) {
addBuildModeFlags(defaultToRelease: false);
argParser
..addOption(
@@ -53,8 +53,12 @@
help: 'Handle machine structured JSON command input and provide output\n'
'and progress in machine friendly format.',
);
+ usesTargetOption();
+ hotRunnerFactory ??= new HotRunnerFactory();
}
+ HotRunnerFactory hotRunnerFactory;
+
@override
final String name = 'attach';
@@ -116,8 +120,9 @@
final FlutterDevice flutterDevice = new FlutterDevice(device,
trackWidgetCreation: false, previewDart2: argResults['preview-dart-2']);
flutterDevice.observatoryUris = <Uri>[ observatoryUri ];
- final HotRunner hotRunner = new HotRunner(
+ final HotRunner hotRunner = hotRunnerFactory.build(
<FlutterDevice>[flutterDevice],
+ target: targetFile,
debuggingOptions: new DebuggingOptions.enabled(getBuildInfo()),
packagesFilePath: globalResults['packages'],
usesTerminalUI: daemon == null,
@@ -145,3 +150,32 @@
Future<void> _validateArguments() async {}
}
+
+class HotRunnerFactory {
+ HotRunner build(List<FlutterDevice> devices, {
+ String target,
+ DebuggingOptions debuggingOptions,
+ bool usesTerminalUI = true,
+ bool benchmarkMode = false,
+ File applicationBinary,
+ bool hostIsIde = false,
+ String projectRootPath,
+ String packagesFilePath,
+ String dillOutputPath,
+ bool stayResident = true,
+ bool ipv6 = false,
+ }) => new HotRunner(
+ devices,
+ target: target,
+ debuggingOptions: debuggingOptions,
+ usesTerminalUI: usesTerminalUI,
+ benchmarkMode: benchmarkMode,
+ applicationBinary: applicationBinary,
+ hostIsIde: hostIsIde,
+ projectRootPath: projectRootPath,
+ packagesFilePath: packagesFilePath,
+ dillOutputPath: dillOutputPath,
+ stayResident: stayResident,
+ ipv6: ipv6,
+ );
+}
\ No newline at end of file
diff --git a/packages/flutter_tools/test/commands/attach_test.dart b/packages/flutter_tools/test/commands/attach_test.dart
index ed1da2c..475b2d0 100644
--- a/packages/flutter_tools/test/commands/attach_test.dart
+++ b/packages/flutter_tools/test/commands/attach_test.dart
@@ -4,10 +4,14 @@
import 'dart:async';
+import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart';
+import 'package:flutter_tools/src/base/file_system.dart';
+import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/attach.dart';
import 'package:flutter_tools/src/device.dart';
+import 'package:flutter_tools/src/run_hot.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart';
@@ -16,8 +20,15 @@
void main() {
group('attach', () {
+ final FileSystem testFileSystem = new MemoryFileSystem(
+ style: platform.isWindows ? FileSystemStyle.windows : FileSystemStyle
+ .posix,
+ );
+
setUpAll(() {
Cache.disableLocking();
+ testFileSystem.directory('lib').createSync();
+ testFileSystem.file('lib/main.dart').createSync();
});
testUsingContext('finds observatory port and forwards', () async {
@@ -30,14 +41,17 @@
// Now that the reader is used, start writing messages to it.
Timer.run(() {
mockLogReader.addLine('Foo');
- mockLogReader.addLine('Observatory listening on http://127.0.0.1:$devicePort');
+ mockLogReader.addLine(
+ 'Observatory listening on http://127.0.0.1:$devicePort');
});
return mockLogReader;
});
when(device.portForwarder).thenReturn(portForwarder);
- when(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort'))).thenAnswer((_) async => hostPort);
- when(portForwarder.forwardedPorts).thenReturn(<ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
+ when(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort')))
+ .thenAnswer((_) async => hostPort);
+ when(portForwarder.forwardedPorts).thenReturn(
+ <ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
when(portForwarder.unforward(any)).thenAnswer((_) async => null);
testDeviceManager.addDevice(device);
@@ -45,10 +59,62 @@
await createTestCommandRunner(command).run(<String>['attach']);
- verify(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort'))).called(1);
+ verify(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort')))
+ .called(1);
mockLogReader.dispose();
- });
+ }, overrides: <Type, Generator>{
+ FileSystem: () => testFileSystem,
+ },
+ );
+
+ testUsingContext('selects specified target', () async {
+ const int devicePort = 499;
+ const int hostPort = 42;
+ final MockDeviceLogReader mockLogReader = new MockDeviceLogReader();
+ final MockPortForwarder portForwarder = new MockPortForwarder();
+ final MockAndroidDevice device = new MockAndroidDevice();
+ final MockHotRunnerFactory mockHotRunnerFactory = new MockHotRunnerFactory();
+ when(device.portForwarder).thenReturn(portForwarder);
+ when(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort')))
+ .thenAnswer((_) async => hostPort);
+ when(portForwarder.forwardedPorts).thenReturn(
+ <ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
+ when(portForwarder.unforward(any)).thenAnswer((_) async => null);
+ when(mockHotRunnerFactory.build(any,
+ target: anyNamed('target'),
+ debuggingOptions: anyNamed('debuggingOptions'),
+ packagesFilePath: anyNamed('packagesFilePath'),
+ usesTerminalUI: anyNamed('usesTerminalUI'))).thenReturn(
+ new MockHotRunner());
+
+ testDeviceManager.addDevice(device);
+ when(device.getLogReader()).thenAnswer((_) {
+ // Now that the reader is used, start writing messages to it.
+ Timer.run(() {
+ mockLogReader.addLine('Foo');
+ mockLogReader.addLine(
+ 'Observatory listening on http://127.0.0.1:$devicePort');
+ });
+
+ return mockLogReader;
+ });
+ final File foo = fs.file('lib/foo.dart')
+ ..createSync();
+
+ final AttachCommand command = new AttachCommand(
+ hotRunnerFactory: mockHotRunnerFactory);
+ await createTestCommandRunner(command).run(
+ <String>['attach', '-t', foo.path, '-v']);
+
+ verify(mockHotRunnerFactory.build(any,
+ target: foo.path,
+ debuggingOptions: anyNamed('debuggingOptions'),
+ packagesFilePath: anyNamed('packagesFilePath'),
+ usesTerminalUI: anyNamed('usesTerminalUI'))).called(1);
+ }, overrides: <Type, Generator>{
+ FileSystem: () => testFileSystem,
+ },);
testUsingContext('forwards to given port', () async {
const int devicePort = 499;
@@ -58,16 +124,20 @@
when(device.portForwarder).thenReturn(portForwarder);
when(portForwarder.forward(devicePort)).thenAnswer((_) async => hostPort);
- when(portForwarder.forwardedPorts).thenReturn(<ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
+ when(portForwarder.forwardedPorts).thenReturn(
+ <ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
when(portForwarder.unforward(any)).thenAnswer((_) async => null);
testDeviceManager.addDevice(device);
final AttachCommand command = new AttachCommand();
- await createTestCommandRunner(command).run(<String>['attach', '--debug-port', '$devicePort']);
+ await createTestCommandRunner(command).run(
+ <String>['attach', '--debug-port', '$devicePort']);
verify(portForwarder.forward(devicePort)).called(1);
- });
+ }, overrides: <Type, Generator>{
+ FileSystem: () => testFileSystem,
+ },);
testUsingContext('exits when no device connected', () async {
final AttachCommand command = new AttachCommand();
@@ -76,7 +146,9 @@
throwsA(isInstanceOf<ToolExit>()),
);
expect(testLogger.statusText, contains('No connected devices'));
- });
+ }, overrides: <Type, Generator>{
+ FileSystem: () => testFileSystem,
+ },);
testUsingContext('exits when multiple devices connected', () async {
Device aDeviceWithId(String id) {
@@ -98,8 +170,14 @@
expect(testLogger.statusText, contains('More than one device'));
expect(testLogger.statusText, contains('xx1'));
expect(testLogger.statusText, contains('yy2'));
- });
+ }, overrides: <Type, Generator>{
+ FileSystem: () => testFileSystem,
+ },);
});
}
class MockPortForwarder extends Mock implements DevicePortForwarder {}
+
+class MockHotRunner extends Mock implements HotRunner {}
+
+class MockHotRunnerFactory extends Mock implements HotRunnerFactory {}