// 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. 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'; import 'package:mockito/mockito.dart'; import '../../src/common.dart'; import '../../src/context.dart'; import '../../src/mocks.dart'; void main() { MemoryFileSystem fileSystem; MockStdio stdio; SymbolizeCommand command; MockDwarfSymbolizationService mockDwarfSymbolizationService; setUpAll(() { Cache.disableLocking(); }); setUp(() { fileSystem = MemoryFileSystem.test(); stdio = MockStdio(); mockDwarfSymbolizationService = MockDwarfSymbolizationService(); command = SymbolizeCommand( stdio: stdio, fileSystem: fileSystem, dwarfSymbolizationService: mockDwarfSymbolizationService, ); 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) .run(const ['symbolize']); expect(result, throwsToolExit(message: '"--debug-info" is required to symbolicate stack traces.')); }); testUsingContext('symbolize exits when --debug-info file is missing', () async { final Future result = createTestCommandRunner(command) .run(const ['symbolize', '--debug-info=app.debug']); expect(result, throwsToolExit(message: 'app.debug does not exist.')); }); testUsingContext('symbolize exits when --input file is missing', () async { fileSystem.file('app.debug').createSync(); final Future result = createTestCommandRunner(command) .run(const ['symbolize', '--debug-info=app.debug', '--input=foo.stack', '--output=results/foo.result']); expect(result, throwsToolExit(message: '')); }); testUsingContext('symbolize succeedes when DwarfSymbolizationService does not throw', () async { fileSystem.file('app.debug').writeAsBytesSync([1, 2, 3]); fileSystem.file('foo.stack').writeAsStringSync('hello'); when(mockDwarfSymbolizationService.decode( input: anyNamed('input'), output: anyNamed('output'), symbols: anyNamed('symbols')) ).thenAnswer((Invocation invocation) async { // Data is passed correctly to service expect((await (invocation.namedArguments[#input] as Stream>).toList()).first, utf8.encode('hello')); expect(invocation.namedArguments[#symbols] as Uint8List, [1, 2, 3,]); return; }); await createTestCommandRunner(command) .run(const ['symbolize', '--debug-info=app.debug', '--input=foo.stack', '--output=results/foo.result']); }); testUsingContext('symbolize throws when DwarfSymbolizationService throws', () async { fileSystem.file('app.debug').writeAsBytesSync([1, 2, 3]); fileSystem.file('foo.stack').writeAsStringSync('hello'); when(mockDwarfSymbolizationService.decode( input: anyNamed('input'), output: anyNamed('output'), symbols: anyNamed('symbols')) ).thenThrow(ToolExit('test')); expect( createTestCommandRunner(command).run(const [ 'symbolize', '--debug-info=app.debug', '--input=foo.stack', '--output=results/foo.result']), throwsToolExit(message: 'test'), ); }); } class MockDwarfSymbolizationService extends Mock implements DwarfSymbolizationService {}