From 712752d2fb180efe268eb255ce3c7e3839fcdb83 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Mon, 6 Jun 2022 10:19:40 -0700 Subject: [PATCH] [flutter_tools] return terminal to echo and line mode before exiting resident_runner (#105283) --- .../flutter_tools/lib/src/commands/run.dart | 4 ++ .../commands.shard/hermetic/run_test.dart | 52 +++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 7e55757ca245..e4ef492c9a8f 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -716,6 +716,10 @@ class RunCommand extends RunCommandBase { throwToolExit('Lost connection to device.'); } rethrow; + } finally { + // However we exited from the runner, ensure the terminal has line mode + // and echo mode enabled before we return the user to the shell. + globals.terminal.singleCharMode = false; } return FlutterCommandResult( ExitStatus.success, diff --git a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart index 1e97718281c6..aab19dfc28e5 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart @@ -23,6 +23,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -47,14 +48,14 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { + setUpAll(() { + Cache.disableLocking(); + }); + group('run', () { FakeDeviceManager mockDeviceManager; FileSystem fileSystem; - setUpAll(() { - Cache.disableLocking(); - }); - setUp(() { mockDeviceManager = FakeDeviceManager(); fileSystem = MemoryFileSystem.test(); @@ -657,6 +658,35 @@ void main() { }); }); + group('terminal', () { + FakeAnsiTerminal fakeTerminal; + + setUp(() { + fakeTerminal = FakeAnsiTerminal(); + }); + + testUsingContext('Flutter run sets terminal singleCharMode to false on exit', () async { + final FakeResidentRunner residentRunner = FakeResidentRunner(); + final TestRunCommandWithFakeResidentRunner command = TestRunCommandWithFakeResidentRunner(); + command.fakeResidentRunner = residentRunner; + + await createTestCommandRunner(command).run([ + 'run', + '--no-pub', + ]); + // The sync completer where we initially set `terminal.singleCharMode` to + // `true` does not execute in unit tests, so explicitly check the + // `setSingleCharModeHistory` that the finally block ran, setting this + // back to `false`. + expect(fakeTerminal.setSingleCharModeHistory, contains(false)); + }, overrides: { + AnsiTerminal: () => fakeTerminal, + Cache: () => Cache.test(processManager: FakeProcessManager.any()), + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), + }); + }); + testUsingContext('Flutter run catches service has disappear errors and throws a tool exit', () async { final FakeResidentRunner residentRunner = FakeResidentRunner(); residentRunner.rpcError = RPCError('flutter._listViews', RPCErrorCodes.kServiceDisappeared, ''); @@ -1021,3 +1051,17 @@ class CapturingAppDomain extends AppDomain { throwToolExit(''); } } + +class FakeAnsiTerminal extends Fake implements AnsiTerminal { + @override + bool usesTerminalUi = false; + + /// A list of all the calls to the [singleCharMode] setter. + List setSingleCharModeHistory = []; + + @override + set singleCharMode(bool value) => setSingleCharModeHistory.add(value); + + @override + bool get singleCharMode => setSingleCharModeHistory.last; +}