| // 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 'package:file/memory.dart'; |
| import 'package:flutter_tools/src/application_package.dart'; |
| import 'package:flutter_tools/src/artifacts.dart'; |
| import 'package:flutter_tools/src/asset.dart'; |
| import 'package:flutter_tools/src/base/file_system.dart'; |
| import 'package:flutter_tools/src/base/io.dart'; |
| import 'package:flutter_tools/src/base/platform.dart'; |
| import 'package:flutter_tools/src/build_info.dart'; |
| import 'package:flutter_tools/src/compile.dart'; |
| import 'package:flutter_tools/src/devfs.dart'; |
| import 'package:flutter_tools/src/device.dart'; |
| import 'package:flutter_tools/src/reporting/reporting.dart'; |
| import 'package:flutter_tools/src/resident_devtools_handler.dart'; |
| import 'package:flutter_tools/src/resident_runner.dart'; |
| import 'package:flutter_tools/src/run_hot.dart'; |
| import 'package:flutter_tools/src/vmservice.dart'; |
| import 'package:meta/meta.dart'; |
| import 'package:package_config/package_config.dart'; |
| import 'package:test/fake.dart'; |
| import 'package:vm_service/vm_service.dart' as vm_service; |
| |
| import '../src/common.dart'; |
| import '../src/context.dart'; |
| import '../src/fake_vm_services.dart'; |
| import '../src/fakes.dart'; |
| |
| final vm_service.Isolate fakeUnpausedIsolate = vm_service.Isolate( |
| id: '1', |
| pauseEvent: vm_service.Event( |
| kind: vm_service.EventKind.kResume, |
| timestamp: 0 |
| ), |
| breakpoints: <vm_service.Breakpoint>[], |
| exceptionPauseMode: null, |
| libraries: <vm_service.LibraryRef>[], |
| livePorts: 0, |
| name: 'test', |
| number: '1', |
| pauseOnExit: false, |
| runnable: true, |
| startTime: 0, |
| isSystemIsolate: false, |
| isolateFlags: <vm_service.IsolateFlag>[], |
| ); |
| |
| final FlutterView fakeFlutterView = FlutterView( |
| id: 'a', |
| uiIsolate: fakeUnpausedIsolate, |
| ); |
| |
| final FakeVmServiceRequest listViews = FakeVmServiceRequest( |
| method: kListViewsMethod, |
| jsonResponse: <String, Object>{ |
| 'views': <Object>[ |
| fakeFlutterView.toJson(), |
| ], |
| }, |
| ); |
| |
| void main() { |
| group('validateReloadReport', () { |
| testUsingContext('invalid', () async { |
| expect(HotRunner.validateReloadReport(vm_service.ReloadReport.parse(<String, dynamic>{ |
| 'type': 'ReloadReport', |
| 'success': false, |
| 'details': <String, dynamic>{}, |
| })), false); |
| expect(HotRunner.validateReloadReport(vm_service.ReloadReport.parse(<String, dynamic>{ |
| 'type': 'ReloadReport', |
| 'success': false, |
| 'details': <String, dynamic>{ |
| 'notices': <Map<String, dynamic>>[ |
| ], |
| }, |
| })), false); |
| expect(HotRunner.validateReloadReport(vm_service.ReloadReport.parse(<String, dynamic>{ |
| 'type': 'ReloadReport', |
| 'success': false, |
| 'details': <String, dynamic>{ |
| 'notices': <String, dynamic>{ |
| 'message': 'error', |
| }, |
| }, |
| })), false); |
| expect(HotRunner.validateReloadReport(vm_service.ReloadReport.parse(<String, dynamic>{ |
| 'type': 'ReloadReport', |
| 'success': false, |
| 'details': <String, dynamic>{ |
| 'notices': <Map<String, dynamic>>[], |
| }, |
| })), false); |
| expect(HotRunner.validateReloadReport(vm_service.ReloadReport.parse(<String, dynamic>{ |
| 'type': 'ReloadReport', |
| 'success': false, |
| 'details': <String, dynamic>{ |
| 'notices': <Map<String, dynamic>>[ |
| <String, dynamic>{'message': false}, |
| ], |
| }, |
| })), false); |
| expect(HotRunner.validateReloadReport(vm_service.ReloadReport.parse(<String, dynamic>{ |
| 'type': 'ReloadReport', |
| 'success': false, |
| 'details': <String, dynamic>{ |
| 'notices': <Map<String, dynamic>>[ |
| <String, dynamic>{'message': <String>['error']}, |
| ], |
| }, |
| })), false); |
| expect(HotRunner.validateReloadReport(vm_service.ReloadReport.parse(<String, dynamic>{ |
| 'type': 'ReloadReport', |
| 'success': false, |
| 'details': <String, dynamic>{ |
| 'notices': <Map<String, dynamic>>[ |
| <String, dynamic>{'message': 'error'}, |
| <String, dynamic>{'message': <String>['error']}, |
| ], |
| }, |
| })), false); |
| expect(HotRunner.validateReloadReport(vm_service.ReloadReport.parse(<String, dynamic>{ |
| 'type': 'ReloadReport', |
| 'success': false, |
| 'details': <String, dynamic>{ |
| 'notices': <Map<String, dynamic>>[ |
| <String, dynamic>{'message': 'error'}, |
| ], |
| }, |
| })), false); |
| expect(HotRunner.validateReloadReport(vm_service.ReloadReport.parse(<String, dynamic>{ |
| 'type': 'ReloadReport', |
| 'success': true, |
| })), true); |
| }); |
| |
| testWithoutContext('ReasonForCancelling toString has a hint for specific errors', () { |
| final ReasonForCancelling reasonForCancelling = ReasonForCancelling( |
| message: 'Const class cannot remove fields', |
| ); |
| |
| expect(reasonForCancelling.toString(), contains('Try performing a hot restart instead.')); |
| }); |
| }); |
| |
| group('hotRestart', () { |
| final FakeResidentCompiler residentCompiler = FakeResidentCompiler(); |
| FileSystem fileSystem; |
| TestUsage testUsage; |
| |
| setUp(() { |
| fileSystem = MemoryFileSystem.test(); |
| testUsage = TestUsage(); |
| }); |
| |
| group('fails to setup', () { |
| TestHotRunnerConfig failingTestingConfig; |
| setUp(() { |
| failingTestingConfig = TestHotRunnerConfig( |
| successfulHotRestartSetup: false, |
| successfulHotReloadSetup: false, |
| ); |
| }); |
| |
| testUsingContext('setupHotRestart function fails', () async { |
| fileSystem.file('.packages') |
| ..createSync(recursive: true) |
| ..writeAsStringSync('\n'); |
| final FakeDevice device = FakeDevice(); |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| FlutterDevice(device, generator: residentCompiler, buildInfo: BuildInfo.debug)..devFS = FakeDevFs(), |
| ]; |
| final OperationResult result = await HotRunner( |
| devices, |
| debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), |
| target: 'main.dart', |
| devtoolsHandler: createNoOpHandler, |
| ).restart(fullRestart: true); |
| expect(result.isOk, false); |
| expect(result.message, 'setupHotRestart failed'); |
| expect(failingTestingConfig.updateDevFSCompleteCalled, false); |
| }, overrides: <Type, Generator>{ |
| HotRunnerConfig: () => failingTestingConfig, |
| Artifacts: () => Artifacts.test(), |
| FileSystem: () => fileSystem, |
| Platform: () => FakePlatform(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('setupHotReload function fails', () async { |
| fileSystem.file('.packages') |
| ..createSync(recursive: true) |
| ..writeAsStringSync('\n'); |
| final FakeDevice device = FakeDevice(); |
| final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| fakeFlutterDevice, |
| ]; |
| final OperationResult result = await HotRunner( |
| devices, |
| debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), |
| target: 'main.dart', |
| devtoolsHandler: createNoOpHandler, |
| reassembleHelper: ( |
| List<FlutterDevice> flutterDevices, |
| Map<FlutterDevice, List<FlutterView>> viewCache, |
| void Function(String message) onSlow, |
| String reloadMessage, |
| String fastReassembleClassName, |
| ) async => ReassembleResult( |
| <FlutterView, FlutterVmService>{null: null}, |
| false, |
| true, |
| ), |
| ).restart(); |
| expect(result.isOk, false); |
| expect(result.message, 'setupHotReload failed'); |
| expect(failingTestingConfig.updateDevFSCompleteCalled, false); |
| }, overrides: <Type, Generator>{ |
| HotRunnerConfig: () => failingTestingConfig, |
| Artifacts: () => Artifacts.test(), |
| FileSystem: () => fileSystem, |
| Platform: () => FakePlatform(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| }); |
| |
| group('shutdown hook tests', () { |
| TestHotRunnerConfig shutdownTestingConfig; |
| |
| setUp(() { |
| shutdownTestingConfig = TestHotRunnerConfig(); |
| }); |
| |
| testUsingContext('shutdown hook called after signal', () async { |
| fileSystem.file('.packages') |
| ..createSync(recursive: true) |
| ..writeAsStringSync('\n'); |
| final FakeDevice device = FakeDevice(); |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| FlutterDevice(device, generator: residentCompiler, buildInfo: BuildInfo.debug), |
| ]; |
| await HotRunner( |
| devices, |
| debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), |
| target: 'main.dart', |
| ).cleanupAfterSignal(); |
| expect(shutdownTestingConfig.shutdownHookCalled, true); |
| }, overrides: <Type, Generator>{ |
| HotRunnerConfig: () => shutdownTestingConfig, |
| Artifacts: () => Artifacts.test(), |
| FileSystem: () => fileSystem, |
| Platform: () => FakePlatform(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('shutdown hook called after app stop', () async { |
| fileSystem.file('.packages') |
| ..createSync(recursive: true) |
| ..writeAsStringSync('\n'); |
| final FakeDevice device = FakeDevice(); |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| FlutterDevice(device, generator: residentCompiler, buildInfo: BuildInfo.debug), |
| ]; |
| await HotRunner( |
| devices, |
| debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), |
| target: 'main.dart', |
| ).preExit(); |
| expect(shutdownTestingConfig.shutdownHookCalled, true); |
| }, overrides: <Type, Generator>{ |
| HotRunnerConfig: () => shutdownTestingConfig, |
| Artifacts: () => Artifacts.test(), |
| FileSystem: () => fileSystem, |
| Platform: () => FakePlatform(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| }); |
| |
| group('successful hot restart', () { |
| TestHotRunnerConfig testingConfig; |
| setUp(() { |
| testingConfig = TestHotRunnerConfig( |
| successfulHotRestartSetup: true, |
| ); |
| }); |
| testUsingContext('correctly tracks time spent for analytics for hot restart', () async { |
| final FakeDevice device = FakeDevice(); |
| final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| fakeFlutterDevice, |
| ]; |
| |
| fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport( |
| success: true, |
| invalidatedSourcesCount: 2, |
| syncedBytes: 4, |
| scannedSourcesCount: 8, |
| compileDuration: const Duration(seconds: 16), |
| transferDuration: const Duration(seconds: 32), |
| ); |
| |
| final FakeStopwatchFactory fakeStopwatchFactory = FakeStopwatchFactory( |
| stopwatches: <String, Stopwatch>{ |
| 'fullRestartHelper': FakeStopwatch()..elapsed = const Duration(seconds: 64), |
| 'updateDevFS': FakeStopwatch()..elapsed = const Duration(seconds: 128), |
| }, |
| ); |
| |
| (fakeFlutterDevice.devFS as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); |
| |
| final OperationResult result = await HotRunner( |
| devices, |
| debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), |
| target: 'main.dart', |
| devtoolsHandler: createNoOpHandler, |
| stopwatchFactory: fakeStopwatchFactory, |
| ).restart(fullRestart: true); |
| |
| expect(result.isOk, true); |
| expect(testUsage.events, <TestUsageEvent>[ |
| const TestUsageEvent('hot', 'restart', parameters: CustomDimensions( |
| hotEventTargetPlatform: 'flutter-tester', |
| hotEventSdkName: 'Tester', |
| hotEventEmulator: false, |
| hotEventFullRestart: true, |
| fastReassemble: false, |
| hotEventOverallTimeInMs: 64000, |
| hotEventSyncedBytes: 4, |
| hotEventInvalidatedSourcesCount: 2, |
| hotEventTransferTimeInMs: 32000, |
| hotEventCompileTimeInMs: 16000, |
| hotEventFindInvalidatedTimeInMs: 128000, |
| hotEventScannedSourcesCount: 8, |
| )), |
| ]); |
| expect(testingConfig.updateDevFSCompleteCalled, true); |
| }, overrides: <Type, Generator>{ |
| HotRunnerConfig: () => testingConfig, |
| Artifacts: () => Artifacts.test(), |
| FileSystem: () => fileSystem, |
| Platform: () => FakePlatform(), |
| ProcessManager: () => FakeProcessManager.any(), |
| Usage: () => testUsage, |
| }); |
| }); |
| |
| group('successful hot reload', () { |
| TestHotRunnerConfig testingConfig; |
| setUp(() { |
| testingConfig = TestHotRunnerConfig( |
| successfulHotReloadSetup: true, |
| ); |
| }); |
| testUsingContext('correctly tracks time spent for analytics for hot reload', () async { |
| final FakeDevice device = FakeDevice(); |
| final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| fakeFlutterDevice, |
| ]; |
| |
| fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport( |
| success: true, |
| invalidatedSourcesCount: 6, |
| syncedBytes: 8, |
| scannedSourcesCount: 16, |
| compileDuration: const Duration(seconds: 16), |
| transferDuration: const Duration(seconds: 32), |
| ); |
| |
| final FakeStopwatchFactory fakeStopwatchFactory = FakeStopwatchFactory( |
| stopwatches: <String, Stopwatch>{ |
| 'updateDevFS': FakeStopwatch()..elapsed = const Duration(seconds: 64), |
| 'reloadSources:reload': FakeStopwatch()..elapsed = const Duration(seconds: 128), |
| 'reloadSources:reassemble': FakeStopwatch()..elapsed = const Duration(seconds: 256), |
| 'reloadSources:vm': FakeStopwatch()..elapsed = const Duration(seconds: 512), |
| }, |
| ); |
| |
| (fakeFlutterDevice.devFS as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); |
| |
| final OperationResult result = await HotRunner( |
| devices, |
| debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), |
| target: 'main.dart', |
| devtoolsHandler: createNoOpHandler, |
| stopwatchFactory: fakeStopwatchFactory, |
| reloadSourcesHelper: ( |
| HotRunner hotRunner, |
| List<FlutterDevice> flutterDevices, |
| bool pause, |
| Map<String, dynamic> firstReloadDetails, |
| String targetPlatform, |
| String sdkName, |
| bool emulator, |
| String reason, |
| ) async { |
| firstReloadDetails['finalLibraryCount'] = 2; |
| firstReloadDetails['receivedLibraryCount'] = 3; |
| firstReloadDetails['receivedClassesCount'] = 4; |
| firstReloadDetails['receivedProceduresCount'] = 5; |
| return OperationResult.ok; |
| }, |
| reassembleHelper: ( |
| List<FlutterDevice> flutterDevices, |
| Map<FlutterDevice, List<FlutterView>> viewCache, |
| void Function(String message) onSlow, |
| String reloadMessage, |
| String fastReassembleClassName, |
| ) async => ReassembleResult( |
| <FlutterView, FlutterVmService>{null: null}, |
| false, |
| true, |
| ), |
| ).restart(); |
| |
| expect(result.isOk, true); |
| expect(testUsage.events, <TestUsageEvent>[ |
| const TestUsageEvent('hot', 'reload', parameters: CustomDimensions( |
| hotEventFinalLibraryCount: 2, |
| hotEventSyncedLibraryCount: 3, |
| hotEventSyncedClassesCount: 4, |
| hotEventSyncedProceduresCount: 5, |
| hotEventSyncedBytes: 8, |
| hotEventInvalidatedSourcesCount: 6, |
| hotEventTransferTimeInMs: 32000, |
| hotEventOverallTimeInMs: 128000, |
| hotEventTargetPlatform: 'flutter-tester', |
| hotEventSdkName: 'Tester', |
| hotEventEmulator: false, |
| hotEventFullRestart: false, |
| fastReassemble: false, |
| hotEventCompileTimeInMs: 16000, |
| hotEventFindInvalidatedTimeInMs: 64000, |
| hotEventScannedSourcesCount: 16, |
| hotEventReassembleTimeInMs: 256000, |
| hotEventReloadVMTimeInMs: 512000, |
| )), |
| ]); |
| expect(testingConfig.updateDevFSCompleteCalled, true); |
| }, overrides: <Type, Generator>{ |
| HotRunnerConfig: () => testingConfig, |
| Artifacts: () => Artifacts.test(), |
| FileSystem: () => fileSystem, |
| Platform: () => FakePlatform(), |
| ProcessManager: () => FakeProcessManager.any(), |
| Usage: () => testUsage, |
| }); |
| }); |
| |
| group('hot restart that failed to sync dev fs', () { |
| TestHotRunnerConfig testingConfig; |
| setUp(() { |
| testingConfig = TestHotRunnerConfig( |
| successfulHotRestartSetup: true, |
| ); |
| }); |
| testUsingContext('still calls the devfs complete callback', () async { |
| final FakeDevice device = FakeDevice(); |
| final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| fakeFlutterDevice, |
| ]; |
| fakeFlutterDevice.updateDevFSReportCallback = () async => throw 'updateDevFS failed'; |
| |
| final HotRunner runner = HotRunner( |
| devices, |
| debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), |
| target: 'main.dart', |
| devtoolsHandler: createNoOpHandler, |
| ); |
| |
| await expectLater(runner.restart(fullRestart: true), throwsA('updateDevFS failed')); |
| expect(testingConfig.updateDevFSCompleteCalled, true); |
| }, overrides: <Type, Generator>{ |
| HotRunnerConfig: () => testingConfig, |
| Artifacts: () => Artifacts.test(), |
| FileSystem: () => fileSystem, |
| Platform: () => FakePlatform(), |
| ProcessManager: () => FakeProcessManager.any(), |
| Usage: () => testUsage, |
| }); |
| }); |
| |
| group('hot reload that failed to sync dev fs', () { |
| TestHotRunnerConfig testingConfig; |
| setUp(() { |
| testingConfig = TestHotRunnerConfig( |
| successfulHotReloadSetup: true, |
| ); |
| }); |
| testUsingContext('still calls the devfs complete callback', () async { |
| final FakeDevice device = FakeDevice(); |
| final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| fakeFlutterDevice, |
| ]; |
| fakeFlutterDevice.updateDevFSReportCallback = () async => throw 'updateDevFS failed'; |
| |
| final HotRunner runner = HotRunner( |
| devices, |
| debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), |
| target: 'main.dart', |
| devtoolsHandler: createNoOpHandler, |
| ); |
| |
| await expectLater(runner.restart(), throwsA('updateDevFS failed')); |
| expect(testingConfig.updateDevFSCompleteCalled, true); |
| }, overrides: <Type, Generator>{ |
| HotRunnerConfig: () => testingConfig, |
| Artifacts: () => Artifacts.test(), |
| FileSystem: () => fileSystem, |
| Platform: () => FakePlatform(), |
| ProcessManager: () => FakeProcessManager.any(), |
| Usage: () => testUsage, |
| }); |
| }); |
| }); |
| |
| group('hot attach', () { |
| FileSystem fileSystem; |
| |
| setUp(() { |
| fileSystem = MemoryFileSystem.test(); |
| }); |
| |
| testUsingContext('Exits with code 2 when HttpException is thrown ' |
| 'during VM service connection', () async { |
| fileSystem.file('.packages') |
| ..createSync(recursive: true) |
| ..writeAsStringSync('\n'); |
| |
| final FakeResidentCompiler residentCompiler = FakeResidentCompiler(); |
| final FakeDevice device = FakeDevice(); |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| TestFlutterDevice( |
| device: device, |
| generator: residentCompiler, |
| exception: const HttpException('Connection closed before full header was received, ' |
| 'uri = http://127.0.0.1:63394/5ZmLv8A59xY=/ws'), |
| ), |
| ]; |
| |
| final int exitCode = await HotRunner(devices, |
| debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), |
| target: 'main.dart', |
| ).attach(); |
| expect(exitCode, 2); |
| }, overrides: <Type, Generator>{ |
| HotRunnerConfig: () => TestHotRunnerConfig(), |
| Artifacts: () => Artifacts.test(), |
| FileSystem: () => fileSystem, |
| Platform: () => FakePlatform(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| }); |
| |
| group('hot cleanupAtFinish()', () { |
| testUsingContext('disposes each device', () async { |
| final FakeDevice device1 = FakeDevice(); |
| final FakeDevice device2 = FakeDevice(); |
| final FakeFlutterDevice flutterDevice1 = FakeFlutterDevice(device1); |
| final FakeFlutterDevice flutterDevice2 = FakeFlutterDevice(device2); |
| |
| final List<FlutterDevice> devices = <FlutterDevice>[ |
| flutterDevice1, |
| flutterDevice2, |
| ]; |
| |
| await HotRunner(devices, |
| debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), |
| target: 'main.dart', |
| ).cleanupAtFinish(); |
| |
| expect(device1.disposed, true); |
| expect(device2.disposed, true); |
| |
| expect(flutterDevice1.stoppedEchoingDeviceLog, true); |
| expect(flutterDevice2.stoppedEchoingDeviceLog, true); |
| }); |
| }); |
| } |
| |
| class FakeDevFs extends Fake implements DevFS { |
| @override |
| Future<void> destroy() async { } |
| |
| @override |
| List<Uri> sources = <Uri>[]; |
| |
| @override |
| DateTime lastCompiled; |
| |
| @override |
| PackageConfig lastPackageConfig; |
| |
| @override |
| Set<String> assetPathsToEvict = <String>{}; |
| |
| @override |
| Uri baseUri; |
| } |
| |
| // Unfortunately Device, despite not being immutable, has an `operator ==`. |
| // Until we fix that, we have to also ignore related lints here. |
| // ignore: avoid_implementing_value_types |
| class FakeDevice extends Fake implements Device { |
| bool disposed = false; |
| |
| @override |
| bool isSupported() => true; |
| |
| @override |
| bool supportsHotReload = true; |
| |
| @override |
| bool supportsHotRestart = true; |
| |
| @override |
| bool supportsFlutterExit = true; |
| |
| @override |
| Future<TargetPlatform> get targetPlatform async => TargetPlatform.tester; |
| |
| @override |
| Future<String> get sdkNameAndVersion async => 'Tester'; |
| |
| @override |
| Future<bool> get isLocalEmulator async => false; |
| |
| @override |
| String get name => 'Fake Device'; |
| |
| @override |
| Future<bool> stopApp( |
| covariant ApplicationPackage app, { |
| String userIdentifier, |
| }) async { |
| return true; |
| } |
| |
| @override |
| Future<void> dispose() async { |
| disposed = true; |
| } |
| } |
| |
| class FakeFlutterDevice extends Fake implements FlutterDevice { |
| FakeFlutterDevice(this.device); |
| |
| bool stoppedEchoingDeviceLog = false; |
| Future<UpdateFSReport> Function() updateDevFSReportCallback; |
| |
| @override |
| final FakeDevice device; |
| |
| @override |
| Future<void> stopEchoingDeviceLog() async { |
| stoppedEchoingDeviceLog = true; |
| } |
| |
| @override |
| DevFS devFS = FakeDevFs(); |
| |
| @override |
| FlutterVmService get vmService => FakeFlutterVmService(); |
| |
| @override |
| ResidentCompiler generator; |
| |
| @override |
| Future<UpdateFSReport> updateDevFS({ |
| Uri mainUri, |
| String target, |
| AssetBundle bundle, |
| DateTime firstBuildTime, |
| bool bundleFirstUpload = false, |
| bool bundleDirty = false, |
| bool fullRestart = false, |
| String projectRootPath, |
| String pathToReload, |
| @required String dillOutputPath, |
| @required List<Uri> invalidatedFiles, |
| @required PackageConfig packageConfig, |
| }) => updateDevFSReportCallback(); |
| } |
| |
| class TestFlutterDevice extends FlutterDevice { |
| TestFlutterDevice({ |
| @required Device device, |
| @required this.exception, |
| @required ResidentCompiler generator, |
| }) : assert(exception != null), |
| super(device, buildInfo: BuildInfo.debug, generator: generator); |
| |
| /// The exception to throw when the connect method is called. |
| final Exception exception; |
| |
| @override |
| Future<void> connect({ |
| ReloadSources reloadSources, |
| Restart restart, |
| CompileExpression compileExpression, |
| GetSkSLMethod getSkSLMethod, |
| PrintStructuredErrorLogMethod printStructuredErrorLogMethod, |
| bool disableServiceAuthCodes = false, |
| bool enableDds = true, |
| bool ipv6 = false, |
| int hostVmServicePort, |
| int ddsPort, |
| bool allowExistingDdsInstance = false, |
| }) async { |
| throw exception; |
| } |
| } |
| |
| class TestHotRunnerConfig extends HotRunnerConfig { |
| TestHotRunnerConfig({this.successfulHotRestartSetup, this.successfulHotReloadSetup}); |
| bool successfulHotRestartSetup; |
| bool successfulHotReloadSetup; |
| bool shutdownHookCalled = false; |
| bool updateDevFSCompleteCalled = false; |
| |
| @override |
| Future<bool> setupHotRestart() async { |
| assert(successfulHotRestartSetup != null, 'setupHotRestart is not expected to be called in this test.'); |
| return successfulHotRestartSetup; |
| } |
| |
| @override |
| Future<bool> setupHotReload() async { |
| assert(successfulHotReloadSetup != null, 'setupHotReload is not expected to be called in this test.'); |
| return successfulHotReloadSetup; |
| } |
| |
| @override |
| void updateDevFSComplete() { |
| updateDevFSCompleteCalled = true; |
| } |
| |
| @override |
| Future<void> runPreShutdownOperations() async { |
| shutdownHookCalled = true; |
| } |
| } |
| |
| class FakeResidentCompiler extends Fake implements ResidentCompiler { |
| @override |
| void accept() {} |
| } |
| |
| class FakeFlutterVmService extends Fake implements FlutterVmService { |
| @override |
| vm_service.VmService get service => FakeVmService(); |
| |
| @override |
| Future<List<FlutterView>> getFlutterViews({bool returnEarly = false, Duration delay = const Duration(milliseconds: 50)}) async { |
| return <FlutterView>[]; |
| } |
| } |
| |
| class FakeVmService extends Fake implements vm_service.VmService { |
| @override |
| Future<vm_service.VM> getVM() async => FakeVm(); |
| } |
| |
| class FakeVm extends Fake implements vm_service.VM { |
| @override |
| List<vm_service.IsolateRef> get isolates => <vm_service.IsolateRef>[]; |
| } |