From 6a390aa7dc68658bfe6679cd098a916fc54e6e69 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 20 Apr 2020 12:21:44 -0700 Subject: [PATCH] [flutter_tools] fix type error in symbolize (#55212) --- .../lib/src/commands/symbolize.dart | 47 ++++++++++++++++--- .../hermetic/symbolize_test.dart | 20 ++++++++ 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/symbolize.dart b/packages/flutter_tools/lib/src/commands/symbolize.dart index c15a9ef0bca..21cf3fae1f7 100644 --- a/packages/flutter_tools/lib/src/commands/symbolize.dart +++ b/packages/flutter_tools/lib/src/commands/symbolize.dart @@ -113,9 +113,46 @@ class SymbolizeCommand extends FlutterCommand { } } +typedef SymbolsTransformer = StreamTransformer Function(Uint8List); + +StreamTransformer _defaultTransformer(Uint8List symbols) { + final Dwarf dwarf = Dwarf.fromBytes(symbols); + if (dwarf == null) { + throwToolExit('Failed to decode symbols file'); + } + return DwarfStackTraceDecoder(dwarf, includeInternalFrames: true); +} + +// A no-op transformer for `DwarfSymbolizationService.test` +StreamTransformer _testTransformer(Uint8List buffer) { + return StreamTransformer.fromHandlers( + handleData: (String data, EventSink sink) { + sink.add(data); + }, + handleDone: (EventSink sink) { + sink.close(); + }, + handleError: (dynamic error, StackTrace stackTrace, EventSink sink) { + sink.addError(error, stackTrace); + } + ); +} + /// A service which decodes stack traces from Dart applications. class DwarfSymbolizationService { - const DwarfSymbolizationService(); + const DwarfSymbolizationService({ + SymbolsTransformer symbolsTransformer = _defaultTransformer, + }) : _transformer = symbolsTransformer; + + /// Create a DwarfSymbolizationService with a no-op transformer for testing. + @visibleForTesting + factory DwarfSymbolizationService.test() { + return const DwarfSymbolizationService( + symbolsTransformer: _testTransformer + ); + } + + final SymbolsTransformer _transformer; /// Decode a stack trace from [input] and place the results in [output]. /// @@ -129,17 +166,13 @@ class DwarfSymbolizationService { @required IOSink output, @required Uint8List symbols, }) async { - final Dwarf dwarf = Dwarf.fromBytes(symbols); - if (dwarf == null) { - throwToolExit('Failed to decode symbols file'); - } - final Completer onDone = Completer(); StreamSubscription subscription; subscription = input + .cast>() .transform(const Utf8Decoder()) .transform(const LineSplitter()) - .transform(DwarfStackTraceDecoder(dwarf, includeInternalFrames: true)) + .transform(_transformer(symbols)) .listen((String line) { try { output.writeln(line); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart index 92118378b54..17c102632b0 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; import 'dart:typed_data'; 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/cache.dart'; import 'package:flutter_tools/src/commands/symbolize.dart'; import 'package:flutter_tools/src/convert.dart'; @@ -38,6 +40,24 @@ void main() { applyMocksToCommand(command); }); + testUsingContext('Regression test for type error in codec', () async { + final DwarfSymbolizationService symbolizationService = DwarfSymbolizationService.test(); + final StreamController> output = StreamController>(); + + unawaited(symbolizationService.decode( + input: Stream.fromIterable([ + utf8.encode('Hello, World\n') as Uint8List, + ]), + symbols: Uint8List(0), + output: IOSink(output.sink), + )); + + await expectLater( + output.stream.transform(utf8.decoder), + emits('Hello, World'), + ); + }); + testUsingContext('symbolize exits when --debug-info argument is missing', () async { final Future result = createTestCommandRunner(command)