diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart index b066f5f78f..aa494a5932 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart @@ -603,9 +603,9 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFile } @override - void handleStderr(List data) { + void handleStderr(String data) { _logTraffic('<== [Flutter] [stderr] $data'); - sendOutput('stderr', utf8.decode(data)); + sendOutput('stderr', data); } /// Handles stdout from the `flutter run --machine` process, decoding the JSON and calling the appropriate handlers. diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_base_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_base_adapter.dart index fd8d848c6d..2032c65c7d 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_base_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_base_adapter.dart @@ -11,6 +11,7 @@ import '../base/file_system.dart'; import '../base/io.dart'; import '../base/platform.dart'; import '../cache.dart'; +import '../convert.dart'; import 'flutter_adapter_args.dart'; import 'mixins.dart'; @@ -150,11 +151,11 @@ abstract class FlutterBaseDebugAdapter extends DartDebugAdapter data); + void handleStderr(String data); void handleStdout(String data); } diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart index 22f83d7ec8..7e1b41b31e 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_test_adapter.dart @@ -105,9 +105,9 @@ class FlutterTestDebugAdapter extends FlutterBaseDebugAdapter with TestAdapter { } @override - void handleStderr(List data) { + void handleStderr(String data) { logger?.call('stderr: $data'); - sendOutput('stderr', utf8.decode(data)); + sendOutput('stderr', data); } /// Handles stdout from the `flutter test --machine` process, decoding the JSON and calling the appropriate handlers. diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart index f659fcf7ad..15b77f90b3 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart @@ -74,7 +74,7 @@ void main() { ); }); - testWithoutContext('logs to client when sendLogsToClient=true', () async { + testWithoutContext('logs stdout to client when sendLogsToClient=true', () async { final BasicProject project = BasicProject(); await project.setUpIn(tempDir); @@ -107,6 +107,35 @@ void main() { ); }); + testWithoutContext('logs stderr to client when sendLogsToClient=true', () async { + final BasicProject project = BasicProject(); + await project.setUpIn(tempDir); + + // Capture all log events. + final Future> logEventsFuture = dap.client.events('dart.log').toList(); + + // Launch the app and wait for it to terminate (because of the error). + await Future.wait(>[ + dap.client.event('terminated'), + dap.client.start( + launch: () => dap.client.launch( + cwd: project.dir.path, + noDebug: true, + toolArgs: ['--not-a-valid-flag'], + sendLogsToClient: true, + ), + ), + ], eagerError: true); + + // Ensure logs contain the expected error message. + final List logEvents = await logEventsFuture; + final List logMessages = logEvents.map((Event l) => (l.body! as Map)['message']! as String).toList(); + expect( + logMessages, + contains(startsWith('<== [Flutter] [stderr] Could not find an option named "not-a-valid-flag"')), + ); + }); + testWithoutContext('can run and terminate a Flutter app in noDebug mode', () async { final BasicProject project = BasicProject(); await project.setUpIn(tempDir);