// 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. // @dart = 2.8 import 'dart:async'; import 'dart:typed_data'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/symbolize.dart'; import 'package:flutter_tools/src/convert.dart'; import 'package:meta/meta.dart'; import 'package:test/fake.dart'; import '../../src/common.dart'; import '../../src/context.dart'; import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { MemoryFileSystem fileSystem; FakeStdio stdio; setUpAll(() { Cache.disableLocking(); }); setUp(() { fileSystem = MemoryFileSystem.test(); stdio = FakeStdio(); }); testUsingContext('Regression test for type error in codec', () async { final DwarfSymbolizationService symbolizationService = DwarfSymbolizationService.test(); final StreamController<List<int>> output = StreamController<List<int>>(); unawaited(symbolizationService.decode( input: Stream<Uint8List>.fromIterable(<Uint8List>[ 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 SymbolizeCommand command = SymbolizeCommand( stdio: stdio, fileSystem: fileSystem, dwarfSymbolizationService: DwarfSymbolizationService.test(), ); final Future<void> result = createTestCommandRunner(command) .run(const <String>['symbolize']); expect(result, throwsToolExit(message: '"--debug-info" is required to symbolize stack traces.')); }, overrides: <Type, Generator>{ OutputPreferences: () => OutputPreferences.test(), }); testUsingContext('symbolize exits when --debug-info file is missing', () async { final SymbolizeCommand command = SymbolizeCommand( stdio: stdio, fileSystem: fileSystem, dwarfSymbolizationService: DwarfSymbolizationService.test(), ); final Future<void> result = createTestCommandRunner(command) .run(const <String>['symbolize', '--debug-info=app.debug']); expect(result, throwsToolExit(message: 'app.debug does not exist.')); }, overrides: <Type, Generator>{ OutputPreferences: () => OutputPreferences.test(), }); testUsingContext('symbolize exits when --input file is missing', () async { final SymbolizeCommand command = SymbolizeCommand( stdio: stdio, fileSystem: fileSystem, dwarfSymbolizationService: DwarfSymbolizationService.test(), ); fileSystem.file('app.debug').createSync(); final Future<void> result = createTestCommandRunner(command) .run(const <String>['symbolize', '--debug-info=app.debug', '--input=foo.stack', '--output=results/foo.result']); expect(result, throwsToolExit(message: '')); }, overrides: <Type, Generator>{ OutputPreferences: () => OutputPreferences.test(), }); testUsingContext('symbolize succeeds when DwarfSymbolizationService does not throw', () async { final SymbolizeCommand command = SymbolizeCommand( stdio: stdio, fileSystem: fileSystem, dwarfSymbolizationService: DwarfSymbolizationService.test(), ); fileSystem.file('app.debug').writeAsBytesSync(<int>[1, 2, 3]); fileSystem.file('foo.stack').writeAsStringSync('hello'); await createTestCommandRunner(command) .run(const <String>['symbolize', '--debug-info=app.debug', '--input=foo.stack', '--output=results/foo.result']); expect(fileSystem.file('results/foo.result'), exists); expect(fileSystem.file('results/foo.result').readAsBytesSync(), <int>[104, 101, 108, 108, 111, 10]); // hello }, overrides: <Type, Generator>{ OutputPreferences: () => OutputPreferences.test(), }); testUsingContext('symbolize throws when DwarfSymbolizationService throws', () async { final SymbolizeCommand command = SymbolizeCommand( stdio: stdio, fileSystem: fileSystem, dwarfSymbolizationService: ThrowingDwarfSymbolizationService(), ); fileSystem.file('app.debug').writeAsBytesSync(<int>[1, 2, 3]); fileSystem.file('foo.stack').writeAsStringSync('hello'); expect( createTestCommandRunner(command).run(const <String>[ 'symbolize', '--debug-info=app.debug', '--input=foo.stack', '--output=results/foo.result']), throwsToolExit(message: 'test'), ); }, overrides: <Type, Generator>{ OutputPreferences: () => OutputPreferences.test(), }); } class ThrowingDwarfSymbolizationService extends Fake implements DwarfSymbolizationService { @override Future<void> decode({ @required Stream<List<int>> input, @required IOSink output, @required Uint8List symbols, }) async { throwToolExit('test'); } }