From 8109dcc2b49b3ea95e231425fade2ff7ff71914a Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Mon, 20 Apr 2020 15:23:09 -0700 Subject: [PATCH] CrashReportSender dependency injection (#54924) --- packages/flutter_tools/lib/runner.dart | 37 +- .../lib/src/reporting/crash_reporting.dart | 49 +- .../lib/src/reporting/reporting.dart | 2 + .../general.shard/crash_reporting_test.dart | 503 +++++++----------- .../general.shard/runner/runner_test.dart | 2 - 5 files changed, 247 insertions(+), 346 deletions(-) diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart index 6b94d8606c8..9520b11d00b 100644 --- a/packages/flutter_tools/lib/runner.dart +++ b/packages/flutter_tools/lib/runner.dart @@ -7,7 +7,7 @@ import 'dart:async'; import 'package:args/command_runner.dart'; import 'package:intl/intl.dart' as intl; import 'package:intl/intl_standalone.dart' as intl_standalone; -import 'package:meta/meta.dart'; +import 'package:http/http.dart' as http; import 'src/base/common.dart'; import 'src/base/context.dart'; @@ -27,13 +27,13 @@ import 'src/runner/flutter_command_runner.dart'; Future run( List args, List commands, { - bool muteCommandLogging = false, - bool verbose = false, - bool verboseHelp = false, - bool reportCrashes, - String flutterVersion, - Map overrides, -}) async { + bool muteCommandLogging = false, + bool verbose = false, + bool verboseHelp = false, + bool reportCrashes, + String flutterVersion, + Map overrides, + }) async { if (muteCommandLogging) { // Remove the verbose option; for help and doctor, users don't need to see // verbose logs. @@ -121,7 +121,14 @@ Future _handleToolError( // Report to both [Usage] and [CrashReportSender]. globals.flutterUsage.sendException(error); - await CrashReportSender.instance.sendReport( + final CrashReportSender crashReportSender = CrashReportSender( + client: http.Client(), + usage: globals.flutterUsage, + platform: globals.platform, + logger: globals.logger, + operatingSystemUtils: globals.os, + ); + await crashReportSender.sendReport( error: error, stackTrace: stackTrace, getFlutterVersion: getFlutterVersion, @@ -184,18 +191,10 @@ String _crashCommand(List args) => 'flutter ${args.join(' ')}'; String _crashException(dynamic error) => '${error.runtimeType}: $error'; -/// File system used by the crash reporting logic. -/// -/// We do not want to use the file system stored in the context because it may -/// be recording. Additionally, in the case of a crash we do not trust the -/// integrity of the [AppContext]. -@visibleForTesting -FileSystem crashFileSystem = const LocalFileSystem(); - /// Saves the crash report to a local file. Future _createLocalCrashReport(List args, dynamic error, StackTrace stackTrace, String doctorText) async { File crashFile = globals.fsUtils.getUniqueFile( - crashFileSystem.currentDirectory, + globals.fs.currentDirectory, 'flutter', 'log', ); @@ -219,7 +218,7 @@ Future _createLocalCrashReport(List args, dynamic error, StackTrac } on FileSystemException catch (_) { // Fallback to the system temporary directory. crashFile = globals.fsUtils.getUniqueFile( - crashFileSystem.systemTempDirectory, + globals.fs.systemTempDirectory, 'flutter', 'log', ); diff --git a/packages/flutter_tools/lib/src/reporting/crash_reporting.dart b/packages/flutter_tools/lib/src/reporting/crash_reporting.dart index ee52f550c7a..04425ec2741 100644 --- a/packages/flutter_tools/lib/src/reporting/crash_reporting.dart +++ b/packages/flutter_tools/lib/src/reporting/crash_reporting.dart @@ -35,28 +35,29 @@ const String _kStackTraceFilename = 'stacktrace_file'; /// environment is behind a firewall and unable to send crash reports to /// Google, or when you wish to use your own server for collecting crash /// reports from Flutter Tools. -/// * In tests call [initializeWith] and provide a mock implementation of -/// [http.Client]. class CrashReportSender { - CrashReportSender._(this._client); + CrashReportSender({ + @required http.Client client, + @required Usage usage, + @required Platform platform, + @required Logger logger, + @required OperatingSystemUtils operatingSystemUtils, + }) : _client = client, + _usage = usage, + _platform = platform, + _logger = logger, + _operatingSystemUtils = operatingSystemUtils; - static CrashReportSender _instance; - - static CrashReportSender get instance => _instance ?? CrashReportSender._(http.Client()); + final http.Client _client; + final Usage _usage; + final Platform _platform; + final Logger _logger; + final OperatingSystemUtils _operatingSystemUtils; bool _crashReportSent = false; - /// Overrides the default [http.Client] with [client] for testing purposes. - @visibleForTesting - static void initializeWith(http.Client client) { - _instance = CrashReportSender._(client); - } - - final http.Client _client; - final Usage _usage = globals.flutterUsage; - Uri get _baseUrl { - final String overrideUrl = globals.platform.environment['FLUTTER_CRASH_SERVER_BASE_URL']; + final String overrideUrl = _platform.environment['FLUTTER_CRASH_SERVER_BASE_URL']; if (overrideUrl != null) { return Uri.parse(overrideUrl); @@ -90,7 +91,7 @@ class CrashReportSender { return; } - globals.printTrace('Sending crash report to Google.'); + _logger.printTrace('Sending crash report to Google.'); final Uri uri = _baseUrl.replace( queryParameters: { @@ -103,8 +104,8 @@ class CrashReportSender { req.fields['uuid'] = _usage.clientId; req.fields['product'] = _kProductId; req.fields['version'] = flutterVersion; - req.fields['osName'] = globals.platform.operatingSystem; - req.fields['osVersion'] = globals.os.name; // this actually includes version + req.fields['osName'] = _platform.operatingSystem; + req.fields['osVersion'] = _operatingSystemUtils.name; // this actually includes version req.fields['type'] = _kDartTypeId; req.fields['error_runtime_type'] = '${error.runtimeType}'; req.fields['error_message'] = '$error'; @@ -120,20 +121,20 @@ class CrashReportSender { if (resp.statusCode == 200) { final String reportId = await http.ByteStream(resp.stream) - .bytesToString(); - globals.printTrace('Crash report sent (report ID: $reportId)'); + .bytesToString(); + _logger.printTrace('Crash report sent (report ID: $reportId)'); _crashReportSent = true; } else { - globals.printError('Failed to send crash report. Server responded with HTTP status code ${resp.statusCode}'); + _logger.printError('Failed to send crash report. Server responded with HTTP status code ${resp.statusCode}'); } // Catch all exceptions to print the message that makes clear that the // crash logger crashed. } catch (sendError, sendStackTrace) { // ignore: avoid_catches_without_on_clauses if (sendError is SocketException || sendError is HttpException) { - globals.printError('Failed to send crash report due to a network error: $sendError'); + _logger.printError('Failed to send crash report due to a network error: $sendError'); } else { // If the sender itself crashes, just print. We did our best. - globals.printError('Crash report sender itself crashed: $sendError\n$sendStackTrace'); + _logger.printError('Crash report sender itself crashed: $sendError\n$sendStackTrace'); } } } diff --git a/packages/flutter_tools/lib/src/reporting/reporting.dart b/packages/flutter_tools/lib/src/reporting/reporting.dart index e583eb4eb22..3666946c27d 100644 --- a/packages/flutter_tools/lib/src/reporting/reporting.dart +++ b/packages/flutter_tools/lib/src/reporting/reporting.dart @@ -10,11 +10,13 @@ import 'package:file/file.dart'; import 'package:http/http.dart' as http; import 'package:intl/intl.dart'; import 'package:meta/meta.dart'; +import 'package:platform/platform.dart'; import 'package:usage/usage_io.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; +import '../base/os.dart'; import '../base/process.dart'; import '../base/time.dart'; import '../build_system/exceptions.dart'; diff --git a/packages/flutter_tools/test/general.shard/crash_reporting_test.dart b/packages/flutter_tools/test/general.shard/crash_reporting_test.dart index fe401d70a53..5162581992e 100644 --- a/packages/flutter_tools/test/general.shard/crash_reporting_test.dart +++ b/packages/flutter_tools/test/general.shard/crash_reporting_test.dart @@ -5,160 +5,205 @@ import 'dart:async'; import 'dart:convert'; -import 'package:file/file.dart'; -import 'package:file/local.dart'; import 'package:file/memory.dart'; -import 'package:flutter_tools/runner.dart' as tools; -import 'package:flutter_tools/src/base/common.dart'; -import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/io.dart'; -import 'package:flutter_tools/src/cache.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; -import 'package:flutter_tools/src/runner/flutter_command.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; import 'package:http/http.dart'; import 'package:http/testing.dart'; -import 'package:quiver/testing/async.dart'; +import 'package:mockito/mockito.dart'; import 'package:platform/platform.dart'; import '../src/common.dart'; import '../src/context.dart'; void main() { - group('crash reporting', () { - setUpAll(() { - Cache.disableLocking(); - }); + BufferLogger logger; + MockUsage mockUsage; + Platform platform; + OperatingSystemUtils operatingSystemUtils; + setUp(() async { + logger = BufferLogger.test(); + + mockUsage = MockUsage(); + when(mockUsage.clientId).thenReturn('00000000-0000-4000-0000-000000000000'); + + platform = FakePlatform(environment: {}, operatingSystem: 'linux'); + operatingSystemUtils = OperatingSystemUtils( + fileSystem: MemoryFileSystem.test(), + logger: logger, + platform: platform, + processManager: FakeProcessManager.any(), + ); + + MockCrashReportSender.sendCalls = 0; + }); + + Future verifyCrashReportSent(RequestInfo crashInfo, { + int crashes = 1, + }) async { + // Verify that we sent the crash report. + expect(crashInfo.method, 'POST'); + expect(crashInfo.uri, Uri( + scheme: 'https', + host: 'clients2.google.com', + port: 443, + path: '/cr/report', + queryParameters: { + 'product': 'Flutter_Tools', + 'version': 'test-version', + }, + )); + expect(crashInfo.fields['uuid'], '00000000-0000-4000-0000-000000000000'); + expect(crashInfo.fields['product'], 'Flutter_Tools'); + expect(crashInfo.fields['version'], 'test-version'); + expect(crashInfo.fields['osName'], 'linux'); + expect(crashInfo.fields['osVersion'], 'Linux'); + expect(crashInfo.fields['type'], 'DartError'); + expect(crashInfo.fields['error_runtime_type'], 'StateError'); + expect(crashInfo.fields['error_message'], 'Bad state: Test bad state error'); + expect(crashInfo.fields['comments'], 'crash'); + + expect(logger.traceText, contains('Sending crash report to Google.')); + expect(logger.traceText, contains('Crash report sent (report ID: test-report-id)')); + } + + testWithoutContext('suppress analytics', () async { + when(mockUsage.suppressAnalytics).thenReturn(true); + + final CrashReportSender crashReportSender = CrashReportSender( + client: CrashingCrashReportSender(const SocketException('no internets')), + usage: mockUsage, + platform: platform, + logger: logger, + operatingSystemUtils: operatingSystemUtils, + ); + + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => 'test-version', + command: 'crash', + ); + + expect(logger.traceText, isEmpty); + }); + + group('allow analytics', () { setUp(() async { - tools.crashFileSystem = MemoryFileSystem(); - setExitFunctionForTests((_) { }); - MockCrashReportSender.sendCalls = 0; + when(mockUsage.suppressAnalytics).thenReturn(false); }); - tearDown(() { - tools.crashFileSystem = const LocalFileSystem(); - restoreExitFunction(); - }); - - testUsingContext('should send crash reports', () async { + testWithoutContext('should send crash reports', () async { final RequestInfo requestInfo = RequestInfo(); - CrashReportSender.initializeWith(MockCrashReportSender(requestInfo)); - final int exitCode = await tools.run( - ['crash'], - [_CrashCommand()], - reportCrashes: true, - flutterVersion: 'test-version', + final CrashReportSender crashReportSender = CrashReportSender( + client: MockCrashReportSender(requestInfo), + usage: mockUsage, + platform: platform, + logger: logger, + operatingSystemUtils: operatingSystemUtils, + ); + + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => 'test-version', + command: 'crash', ); - expect(exitCode, 1); await verifyCrashReportSent(requestInfo); - }, overrides: { - Stdio: () => _NoStderr(), }); - testUsingContext('should print an explanatory message when there is a SocketException', () async { - final Completer exitCodeCompleter = Completer(); - setExitFunctionForTests((int exitCode) { - exitCodeCompleter.complete(exitCode); - }); + testWithoutContext('should print an explanatory message when there is a SocketException', () async { + final CrashReportSender crashReportSender = CrashReportSender( + client: CrashingCrashReportSender(const SocketException('no internets')), + usage: mockUsage, + platform: platform, + logger: logger, + operatingSystemUtils: operatingSystemUtils, + ); - CrashReportSender.initializeWith( - CrashingCrashReportSender(const SocketException('no internets'))); + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => 'test-version', + command: 'crash', + ); - unawaited(tools.run( - ['crash'], - [_CrashAsyncCommand()], - reportCrashes: true, - flutterVersion: 'test-version', - )); - expect(await exitCodeCompleter.future, 1); - expect(testLogger.errorText, contains('Failed to send crash report due to a network error')); - }, overrides: { - Stdio: () => _NoStderr(), + expect(logger.errorText, contains('Failed to send crash report due to a network error')); }); - testUsingContext('should print an explanatory message when there is an HttpException', () async { - final Completer exitCodeCompleter = Completer(); - setExitFunctionForTests((int exitCode) { - exitCodeCompleter.complete(exitCode); - }); + testWithoutContext('should print an explanatory message when there is an HttpException', () async { + final CrashReportSender crashReportSender = CrashReportSender( + client: CrashingCrashReportSender(const HttpException('no internets')), + usage: mockUsage, + platform: platform, + logger: logger, + operatingSystemUtils: operatingSystemUtils, + ); - CrashReportSender.initializeWith( - CrashingCrashReportSender(const HttpException('no internets'))); + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => 'test-version', + command: 'crash', + ); - unawaited(tools.run( - ['crash'], - [_CrashAsyncCommand()], - reportCrashes: true, - flutterVersion: 'test-version', - )); - expect(await exitCodeCompleter.future, 1); - expect(testLogger.errorText, contains('Failed to send crash report due to a network error')); - }, overrides: { - Stdio: () => _NoStderr(), + expect(logger.errorText, contains('Failed to send crash report due to a network error')); }); - testUsingContext('should send crash reports when async throws', () async { - final Completer exitCodeCompleter = Completer(); - setExitFunctionForTests((int exitCode) { - exitCodeCompleter.complete(exitCode); - }); - + testWithoutContext('should send only one crash report when sent many times', () async { final RequestInfo requestInfo = RequestInfo(); - CrashReportSender.initializeWith(MockCrashReportSender(requestInfo)); + final CrashReportSender crashReportSender = CrashReportSender( + client: MockCrashReportSender(requestInfo), + usage: mockUsage, + platform: platform, + logger: logger, + operatingSystemUtils: operatingSystemUtils, + ); - unawaited(tools.run( - ['crash'], - [_CrashAsyncCommand()], - reportCrashes: true, - flutterVersion: 'test-version', - )); - expect(await exitCodeCompleter.future, 1); - await verifyCrashReportSent(requestInfo); - }, overrides: { - Stdio: () => _NoStderr(), - }); + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => 'test-version', + command: 'crash', + ); - testUsingContext('should send only one crash report when async throws many', () async { - final Completer exitCodeCompleter = Completer(); - setExitFunctionForTests((int exitCode) { - if (!exitCodeCompleter.isCompleted) { - exitCodeCompleter.complete(exitCode); - } - }); + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => 'test-version', + command: 'crash', + ); - final RequestInfo requestInfo = RequestInfo(); - final MockCrashReportSender sender = MockCrashReportSender(requestInfo); - CrashReportSender.initializeWith(sender); + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => 'test-version', + command: 'crash', + ); + + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => 'test-version', + command: 'crash', + ); - FakeAsync().run((FakeAsync time) { - time.elapse(const Duration(seconds: 1)); - unawaited(tools.run( - ['crash'], - [_MultiCrashAsyncCommand(crashes: 4)], - reportCrashes: true, - flutterVersion: 'test-version', - )); - time.elapse(const Duration(seconds: 1)); - time.flushMicrotasks(); - }); - expect(await exitCodeCompleter.future, 1); expect(MockCrashReportSender.sendCalls, 1); await verifyCrashReportSent(requestInfo, crashes: 4); - }, overrides: { - DoctorValidatorsProvider: () => FakeDoctorValidatorsProvider(), - Stdio: () => _NoStderr(), }); - testUsingContext('should not send a crash report if on a user-branch', () async { + testWithoutContext('should not send a crash report if on a user-branch', () async { String method; Uri uri; - CrashReportSender.initializeWith(MockClient((Request request) async { + final MockClient mockClient = MockClient((Request request) async { method = request.method; uri = request.url; @@ -166,41 +211,60 @@ void main() { 'test-report-id', 200, ); - })); + }); - final int exitCode = await tools.run( - ['crash'], - [_CrashCommand()], - reportCrashes: true, - flutterVersion: '[user-branch]/v1.2.3', + final CrashReportSender crashReportSender = CrashReportSender( + client: mockClient, + usage: mockUsage, + platform: platform, + logger: logger, + operatingSystemUtils: operatingSystemUtils, ); - expect(exitCode, 1); + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => '[user-branch]/v1.2.3', + command: 'crash', + ); // Verify that the report wasn't sent expect(method, null); expect(uri, null); - expect(testLogger.traceText, isNot(contains('Crash report sent'))); - }, overrides: { - Stdio: () => _NoStderr(), + expect(logger.traceText, isNot(contains('Crash report sent'))); }); - testUsingContext('can override base URL', () async { + testWithoutContext('can override base URL', () async { Uri uri; - CrashReportSender.initializeWith(MockClient((Request request) async { + final MockClient mockClient = MockClient((Request request) async { uri = request.url; return Response('test-report-id', 200); - })); + }); - final int exitCode = await tools.run( - ['crash'], - [_CrashCommand()], - reportCrashes: true, - flutterVersion: 'test-version', + final Platform environmentPlatform = FakePlatform( + operatingSystem: 'linux', + environment: { + 'HOME': '/', + 'FLUTTER_CRASH_SERVER_BASE_URL': 'https://localhost:12345/fake_server', + }, + script: Uri(scheme: 'data'), ); - expect(exitCode, 1); + final CrashReportSender crashReportSender = CrashReportSender( + client: mockClient, + usage: mockUsage, + platform: environmentPlatform, + logger: logger, + operatingSystemUtils: operatingSystemUtils, + ); + + await crashReportSender.sendReport( + error: StateError('Test bad state error'), + stackTrace: null, + getFlutterVersion: () => 'test-version', + command: 'crash', + ); // Verify that we sent the crash report. expect(uri, isNotNull); @@ -214,16 +278,6 @@ void main() { 'version': 'test-version', }, )); - }, overrides: { - Platform: () => FakePlatform( - operatingSystem: 'linux', - environment: { - 'HOME': '/', - 'FLUTTER_CRASH_SERVER_BASE_URL': 'https://localhost:12345/fake_server', - }, - script: Uri(scheme: 'data'), - ), - Stdio: () => _NoStderr(), }); }); } @@ -234,42 +288,6 @@ class RequestInfo { Map fields; } -Future verifyCrashReportSent(RequestInfo crashInfo, { - int crashes = 1, -}) async { - // Verify that we sent the crash report. - expect(crashInfo.method, 'POST'); - expect(crashInfo.uri, Uri( - scheme: 'https', - host: 'clients2.google.com', - port: 443, - path: '/cr/report', - queryParameters: { - 'product': 'Flutter_Tools', - 'version': 'test-version', - }, - )); - expect(crashInfo.fields['uuid'], '00000000-0000-4000-0000-000000000000'); - expect(crashInfo.fields['product'], 'Flutter_Tools'); - expect(crashInfo.fields['version'], 'test-version'); - expect(crashInfo.fields['osName'], globals.platform.operatingSystem); - expect(crashInfo.fields['osVersion'], 'fake OS name and version'); - expect(crashInfo.fields['type'], 'DartError'); - expect(crashInfo.fields['error_runtime_type'], 'StateError'); - expect(crashInfo.fields['error_message'], 'Bad state: Test bad state error'); - expect(crashInfo.fields['comments'], 'crash'); - - expect(testLogger.traceText, contains('Sending crash report to Google.')); - expect(testLogger.traceText, contains('Crash report sent (report ID: test-report-id)')); - - // Verify that we've written the crash report to disk. - final List writtenFiles = - (await tools.crashFileSystem.directory('/').list(recursive: true).toList()) - .map((FileSystemEntity e) => e.path).toList(); - expect(writtenFiles, hasLength(crashes)); - expect(writtenFiles, contains('flutter_01.log')); -} - class MockCrashReportSender extends MockClient { MockCrashReportSender(RequestInfo crashInfo) : super((Request request) async { MockCrashReportSender.sendCalls++; @@ -283,14 +301,14 @@ class MockCrashReportSender extends MockClient { utf8.decode(request.bodyBytes) .split('--$boundary') .map>((String part) { - final Match nameMatch = RegExp(r'name="(.*)"').firstMatch(part); - if (nameMatch == null) { - return null; - } - final String name = nameMatch[1]; - final String value = part.split('\n').skip(2).join('\n').trim(); - return [name, value]; - }) + final Match nameMatch = RegExp(r'name="(.*)"').firstMatch(part); + if (nameMatch == null) { + return null; + } + final String name = nameMatch[1]; + final String value = part.split('\n').skip(2).join('\n').trim(); + return [name, value]; + }) .where((List pair) => pair != null), key: (dynamic key) { final List pair = key as List; @@ -317,78 +335,6 @@ class CrashingCrashReportSender extends MockClient { }); } -/// Throws a random error to simulate a CLI crash. -class _CrashCommand extends FlutterCommand { - - @override - String get description => 'Simulates a crash'; - - @override - String get name => 'crash'; - - @override - Future runCommand() async { - void fn1() { - throw StateError('Test bad state error'); - } - - void fn2() { - fn1(); - } - - void fn3() { - fn2(); - } - - fn3(); - - return FlutterCommandResult.success(); - } -} - -/// Throws StateError from async callback. -class _CrashAsyncCommand extends FlutterCommand { - - @override - String get description => 'Simulates a crash'; - - @override - String get name => 'crash'; - - @override - Future runCommand() async { - Timer.run(() { - throw StateError('Test bad state error'); - }); - return Completer().future; // expect StateError - } -} - -/// Generates multiple asynchronous unhandled exceptions. -class _MultiCrashAsyncCommand extends FlutterCommand { - _MultiCrashAsyncCommand({ - int crashes = 1, - }) : _crashes = crashes; - - final int _crashes; - - @override - String get description => 'Simulates a crash'; - - @override - String get name => 'crash'; - - @override - Future runCommand() async { - for (int i = 0; i < _crashes; i++) { - Timer.run(() { - throw StateError('Test bad state error'); - }); - } - return Completer().future; // expect StateError - } -} - /// A DoctorValidatorsProvider that overrides the default validators without /// overriding the doctor. class FakeDoctorValidatorsProvider implements DoctorValidatorsProvider { @@ -399,49 +345,4 @@ class FakeDoctorValidatorsProvider implements DoctorValidatorsProvider { List get workflows => []; } -class _NoStderr extends Stdio { - _NoStderr(); - - @override - IOSink get stderr => const _NoopIOSink(); -} - -class _NoopIOSink implements IOSink { - const _NoopIOSink(); - - @override - Encoding get encoding => utf8; - - @override - set encoding(_) => throw UnsupportedError(''); - - @override - void add(_) { } - - @override - void write(_) { } - - @override - void writeAll(_, [ __ = '' ]) { } - - @override - void writeln([ _ = '' ]) { } - - @override - void writeCharCode(_) { } - - @override - void addError(_, [ __ ]) { } - - @override - Future addStream(_) async { } - - @override - Future flush() async { } - - @override - Future close() async { } - - @override - Future get done async { } -} +class MockUsage extends Mock implements Usage {} diff --git a/packages/flutter_tools/test/general.shard/runner/runner_test.dart b/packages/flutter_tools/test/general.shard/runner/runner_test.dart index 38ff6a47146..44d3d793ca1 100644 --- a/packages/flutter_tools/test/general.shard/runner/runner_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/runner_test.dart @@ -24,7 +24,6 @@ void main() { MockGitHubTemplateCreator mockGitHubTemplateCreator; setUp(() { mockGitHubTemplateCreator = MockGitHubTemplateCreator(); - runner.crashFileSystem = MemoryFileSystem(); // Instead of exiting with dart:io exit(), this causes an exception to // be thrown, which we catch with the onError callback in the zone below. io.setExitFunctionForTests((int _) { throw 'test exit';}); @@ -32,7 +31,6 @@ void main() { }); tearDown(() { - runner.crashFileSystem = const LocalFileSystem(); io.restoreExitFunction(); Cache.enableLocking(); });