CrashReportSender dependency injection (#54924)

diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart
index 6b94d86..9520b11 100644
--- a/packages/flutter_tools/lib/runner.dart
+++ b/packages/flutter_tools/lib/runner.dart
@@ -7,7 +7,7 @@
 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 @@
 Future<int> run(
   List<String> args,
   List<FlutterCommand> commands, {
-  bool muteCommandLogging = false,
-  bool verbose = false,
-  bool verboseHelp = false,
-  bool reportCrashes,
-  String flutterVersion,
-  Map<Type, Generator> overrides,
-}) async {
+    bool muteCommandLogging = false,
+    bool verbose = false,
+    bool verboseHelp = false,
+    bool reportCrashes,
+    String flutterVersion,
+    Map<Type, Generator> overrides,
+  }) async {
   if (muteCommandLogging) {
     // Remove the verbose option; for help and doctor, users don't need to see
     // verbose logs.
@@ -121,7 +121,14 @@
 
     // 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 _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<File> _createLocalCrashReport(List<String> args, dynamic error, StackTrace stackTrace, String doctorText) async {
   File crashFile = globals.fsUtils.getUniqueFile(
-    crashFileSystem.currentDirectory,
+    globals.fs.currentDirectory,
     'flutter',
     'log',
   );
@@ -219,7 +218,7 @@
   } 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 ee52f55..04425ec 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 @@
 ///   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 @@
         return;
       }
 
-      globals.printTrace('Sending crash report to Google.');
+      _logger.printTrace('Sending crash report to Google.');
 
       final Uri uri = _baseUrl.replace(
         queryParameters: <String, String>{
@@ -103,8 +104,8 @@
       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 @@
 
       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 e583eb4..3666946 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: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 fe401d7..5162581 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: <String, String>{}, operatingSystem: 'linux');
+    operatingSystemUtils = OperatingSystemUtils(
+      fileSystem: MemoryFileSystem.test(),
+      logger: logger,
+      platform: platform,
+      processManager: FakeProcessManager.any(),
+    );
+
+    MockCrashReportSender.sendCalls = 0;
+  });
+
+  Future<void> 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: <String, String>{
+        '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(
-        <String>['crash'],
-        <FlutterCommand>[_CrashCommand()],
-        reportCrashes: true,
-        flutterVersion: 'test-version',
+      final CrashReportSender crashReportSender = CrashReportSender(
+        client: MockCrashReportSender(requestInfo),
+        usage: mockUsage,
+        platform: platform,
+        logger: logger,
+        operatingSystemUtils: operatingSystemUtils,
       );
-      expect(exitCode, 1);
+
+      await crashReportSender.sendReport(
+        error: StateError('Test bad state error'),
+        stackTrace: null,
+        getFlutterVersion: () => 'test-version',
+        command: 'crash',
+      );
 
       await verifyCrashReportSent(requestInfo);
-    }, overrides: <Type, Generator>{
-      Stdio: () => _NoStderr(),
     });
 
-    testUsingContext('should print an explanatory message when there is a SocketException', () async {
-      final Completer<int> exitCodeCompleter = Completer<int>();
-      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(
-        <String>['crash'],
-        <FlutterCommand>[_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: <Type, Generator>{
-      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<int> exitCodeCompleter = Completer<int>();
-      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(
-        <String>['crash'],
-        <FlutterCommand>[_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: <Type, Generator>{
-      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<int> exitCodeCompleter = Completer<int>();
-      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(
-        <String>['crash'],
-        <FlutterCommand>[_CrashAsyncCommand()],
-        reportCrashes: true,
-        flutterVersion: 'test-version',
-      ));
-      expect(await exitCodeCompleter.future, 1);
-      await verifyCrashReportSent(requestInfo);
-    }, overrides: <Type, Generator>{
-      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<int> exitCodeCompleter = Completer<int>();
-      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',
+      );
 
-      FakeAsync().run((FakeAsync time) {
-        time.elapse(const Duration(seconds: 1));
-        unawaited(tools.run(
-          <String>['crash'],
-          <FlutterCommand>[_MultiCrashAsyncCommand(crashes: 4)],
-          reportCrashes: true,
-          flutterVersion: 'test-version',
-        ));
-        time.elapse(const Duration(seconds: 1));
-        time.flushMicrotasks();
-      });
-      expect(await exitCodeCompleter.future, 1);
+      await crashReportSender.sendReport(
+        error: StateError('Test bad state error'),
+        stackTrace: null,
+        getFlutterVersion: () => 'test-version',
+        command: 'crash',
+      );
+
       expect(MockCrashReportSender.sendCalls, 1);
       await verifyCrashReportSent(requestInfo, crashes: 4);
-    }, overrides: <Type, Generator>{
-      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 @@
           'test-report-id',
           200,
         );
-      }));
+      });
 
-      final int exitCode = await tools.run(
-        <String>['crash'],
-        <FlutterCommand>[_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: <Type, Generator>{
-      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(
-        <String>['crash'],
-        <FlutterCommand>[_CrashCommand()],
-        reportCrashes: true,
-        flutterVersion: 'test-version',
+      final Platform environmentPlatform = FakePlatform(
+        operatingSystem: 'linux',
+        environment: <String, String>{
+          '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 @@
           'version': 'test-version',
         },
       ));
-    }, overrides: <Type, Generator>{
-      Platform: () => FakePlatform(
-        operatingSystem: 'linux',
-        environment: <String, String>{
-          'HOME': '/',
-          'FLUTTER_CRASH_SERVER_BASE_URL': 'https://localhost:12345/fake_server',
-        },
-        script: Uri(scheme: 'data'),
-      ),
-      Stdio: () => _NoStderr(),
     });
   });
 }
@@ -234,42 +288,6 @@
   Map<String, String> fields;
 }
 
-Future<void> 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: <String, String>{
-      '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<String> 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 @@
       utf8.decode(request.bodyBytes)
         .split('--$boundary')
         .map<List<String>>((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 <String>[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 <String>[name, value];
+      })
         .where((List<String> pair) => pair != null),
       key: (dynamic key) {
         final List<String> pair = key as List<String>;
@@ -317,78 +335,6 @@
   });
 }
 
-/// 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<FlutterCommandResult> 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<FlutterCommandResult> runCommand() async {
-    Timer.run(() {
-      throw StateError('Test bad state error');
-    });
-    return Completer<FlutterCommandResult>().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<FlutterCommandResult> runCommand() async {
-    for (int i = 0; i < _crashes; i++) {
-      Timer.run(() {
-        throw StateError('Test bad state error');
-      });
-    }
-    return Completer<FlutterCommandResult>().future; // expect StateError
-  }
-}
-
 /// A DoctorValidatorsProvider that overrides the default validators without
 /// overriding the doctor.
 class FakeDoctorValidatorsProvider implements DoctorValidatorsProvider {
@@ -399,49 +345,4 @@
   List<Workflow> get workflows => <Workflow>[];
 }
 
-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<dynamic> addStream(_) async { }
-
-  @override
-  Future<dynamic> flush() async { }
-
-  @override
-  Future<dynamic> close() async { }
-
-  @override
-  Future<dynamic> 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 38ff6a4..44d3d79 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 @@
     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 @@
     });
 
     tearDown(() {
-      runner.crashFileSystem = const LocalFileSystem();
       io.restoreExitFunction();
       Cache.enableLocking();
     });