| // 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 'package:file/file.dart'; |
| import 'package:file/memory.dart'; |
| import 'package:file_testing/file_testing.dart'; |
| import 'package:flutter_tools/src/base/io.dart'; |
| import 'package:flutter_tools/src/base/logger.dart'; |
| import 'package:flutter_tools/src/base/signals.dart'; |
| import 'package:flutter_tools/src/base/terminal.dart'; |
| import 'package:flutter_tools/src/build_info.dart'; |
| import 'package:flutter_tools/src/build_system/targets/shader_compiler.dart'; |
| import 'package:flutter_tools/src/compile.dart'; |
| import 'package:flutter_tools/src/convert.dart'; |
| import 'package:flutter_tools/src/devfs.dart'; |
| import 'package:flutter_tools/src/device.dart'; |
| import 'package:flutter_tools/src/resident_devtools_handler.dart'; |
| import 'package:flutter_tools/src/resident_runner.dart'; |
| import 'package:flutter_tools/src/vmservice.dart'; |
| import 'package:test/fake.dart'; |
| import 'package:vm_service/vm_service.dart' as vm_service; |
| |
| import '../src/common.dart'; |
| import '../src/fake_vm_services.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>[], |
| extensionRPCs: <String>[], |
| libraries: <vm_service.LibraryRef>[ |
| vm_service.LibraryRef( |
| id: '1', |
| uri: 'file:///hello_world/main.dart', |
| name: '', |
| ), |
| ], |
| 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() { |
| testWithoutContext('keyboard input handling single help character', () async { |
| final TestRunner testRunner = TestRunner(); |
| final Logger logger = BufferLogger.test(); |
| final Signals signals = Signals.test(); |
| final Terminal terminal = Terminal.test(); |
| final MemoryFileSystem fs = MemoryFileSystem.test(); |
| final ProcessInfo processInfo = ProcessInfo.test(fs); |
| final TerminalHandler terminalHandler = TerminalHandler( |
| testRunner, |
| logger: logger, |
| signals: signals, |
| terminal: terminal, |
| processInfo: processInfo, |
| reportReady: false, |
| ); |
| |
| expect(testRunner.hasHelpBeenPrinted, false); |
| await terminalHandler.processTerminalInput('h'); |
| expect(testRunner.hasHelpBeenPrinted, true); |
| }); |
| |
| testWithoutContext('keyboard input handling help character surrounded with newlines', () async { |
| final TestRunner testRunner = TestRunner(); |
| final Logger logger = BufferLogger.test(); |
| final Signals signals = Signals.test(); |
| final Terminal terminal = Terminal.test(); |
| final MemoryFileSystem fs = MemoryFileSystem.test(); |
| final ProcessInfo processInfo = ProcessInfo.test(fs); |
| final TerminalHandler terminalHandler = TerminalHandler( |
| testRunner, |
| logger: logger, |
| signals: signals, |
| terminal: terminal, |
| processInfo: processInfo, |
| reportReady: false, |
| ); |
| |
| expect(testRunner.hasHelpBeenPrinted, false); |
| await terminalHandler.processTerminalInput('\nh\n'); |
| expect(testRunner.hasHelpBeenPrinted, true); |
| }); |
| |
| group('keycode verification, brought to you by the letter', () { |
| testWithoutContext('a, can handle trailing newlines', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('a\n'); |
| |
| expect(terminalHandler.lastReceivedCommand, 'a'); |
| }); |
| |
| testWithoutContext('n, can handle trailing only newlines', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[]); |
| await terminalHandler.processTerminalInput('\n\n'); |
| |
| expect(terminalHandler.lastReceivedCommand, ''); |
| }); |
| |
| testWithoutContext('a - debugToggleProfileWidgetBuilds', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.profileWidgetBuilds', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'enabled': 'false', |
| }, |
| ), |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.profileWidgetBuilds', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| 'enabled': 'true', |
| }, |
| jsonResponse: <String, Object>{ |
| 'enabled': 'true', |
| }, |
| ), |
| ]); |
| |
| await terminalHandler.processTerminalInput('a'); |
| }); |
| |
| testWithoutContext('a - debugToggleProfileWidgetBuilds with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.profileWidgetBuilds', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'enabled': 'false', |
| }, |
| ), |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.profileWidgetBuilds', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| 'enabled': 'true', |
| }, |
| jsonResponse: <String, Object>{ |
| 'enabled': 'true', |
| }, |
| ), |
| ], web: true); |
| |
| await terminalHandler.processTerminalInput('a'); |
| }); |
| |
| testWithoutContext('j unsupported jank metrics for web', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], web: true); |
| await terminalHandler.processTerminalInput('j'); |
| expect(terminalHandler.logger.warningText.contains('Unable to get jank metrics for web'), true); |
| }); |
| |
| testWithoutContext('a - debugToggleProfileWidgetBuilds without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| |
| await terminalHandler.processTerminalInput('a'); |
| }); |
| |
| testWithoutContext('b - debugToggleBrightness', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.brightnessOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'Brightness.light', |
| } |
| ), |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.brightnessOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| 'value': 'Brightness.dark', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'Brightness.dark', |
| } |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('b'); |
| |
| expect(terminalHandler.logger.statusText, contains('Changed brightness to Brightness.dark')); |
| }); |
| |
| testWithoutContext('b - debugToggleBrightness with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.brightnessOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'Brightness.light', |
| } |
| ), |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.brightnessOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| 'value': 'Brightness.dark', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'Brightness.dark', |
| } |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('b'); |
| |
| expect(terminalHandler.logger.statusText, contains('Changed brightness to Brightness.dark')); |
| }); |
| |
| testWithoutContext('b - debugToggleBrightness without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| |
| await terminalHandler.processTerminalInput('b'); |
| }); |
| |
| testWithoutContext('d,D - detach', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[]); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| await terminalHandler.processTerminalInput('d'); |
| |
| expect(runner.calledDetach, true); |
| runner.calledDetach = false; |
| |
| await terminalHandler.processTerminalInput('D'); |
| |
| expect(runner.calledDetach, true); |
| }); |
| |
| testWithoutContext('h,H,? - printHelp', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[]); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| await terminalHandler.processTerminalInput('h'); |
| |
| expect(runner.calledPrintWithDetails, true); |
| runner.calledPrintWithDetails = false; |
| |
| await terminalHandler.processTerminalInput('H'); |
| |
| expect(runner.calledPrintWithDetails, true); |
| runner.calledPrintWithDetails = false; |
| |
| await terminalHandler.processTerminalInput('?'); |
| |
| expect(runner.calledPrintWithDetails, true); |
| }); |
| |
| testWithoutContext('i - debugToggleWidgetInspector', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.inspector.show', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| ]); |
| |
| await terminalHandler.processTerminalInput('i'); |
| }); |
| |
| testWithoutContext('i - debugToggleWidgetInspector with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.inspector.show', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| ], web: true); |
| |
| await terminalHandler.processTerminalInput('i'); |
| }); |
| |
| testWithoutContext('i - debugToggleWidgetInspector without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| |
| await terminalHandler.processTerminalInput('i'); |
| }); |
| |
| testWithoutContext('I - debugToggleInvertOversizedImages', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.invertOversizedImages', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('I'); |
| }); |
| |
| testWithoutContext('I - debugToggleInvertOversizedImages with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.invertOversizedImages', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('I'); |
| }); |
| |
| testWithoutContext('I - debugToggleInvertOversizedImages without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('I'); |
| }); |
| |
| testWithoutContext('I - debugToggleInvertOversizedImages in profile mode is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], buildMode: BuildMode.profile); |
| await terminalHandler.processTerminalInput('I'); |
| }); |
| |
| testWithoutContext('L - debugDumpLayerTree', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpLayerTree', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'LAYER TREE', |
| } |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('L'); |
| |
| expect(terminalHandler.logger.statusText, contains('LAYER TREE')); |
| }); |
| |
| testWithoutContext('L - debugDumpLayerTree with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpLayerTree', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'LAYER TREE', |
| } |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('L'); |
| |
| expect(terminalHandler.logger.statusText, contains('LAYER TREE')); |
| }); |
| |
| testWithoutContext('L - debugDumpLayerTree with service protocol and profile mode is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], buildMode: BuildMode.profile); |
| await terminalHandler.processTerminalInput('L'); |
| }); |
| |
| testWithoutContext('L - debugDumpLayerTree without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('L'); |
| }); |
| |
| testWithoutContext('f - debugDumpFocusTree', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpFocusTree', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'FOCUS TREE', |
| } |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('f'); |
| |
| expect(terminalHandler.logger.statusText, contains('FOCUS TREE')); |
| }); |
| |
| testWithoutContext('f - debugDumpLayerTree with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpFocusTree', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'FOCUS TREE', |
| } |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('f'); |
| |
| expect(terminalHandler.logger.statusText, contains('FOCUS TREE')); |
| }); |
| |
| testWithoutContext('f - debugDumpFocusTree with service protocol and profile mode is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], buildMode: BuildMode.profile); |
| await terminalHandler.processTerminalInput('f'); |
| }); |
| |
| testWithoutContext('f - debugDumpFocusTree without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('f'); |
| }); |
| |
| testWithoutContext('o,O - debugTogglePlatform', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| // Request 1. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.platformOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'iOS', |
| }, |
| ), |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.platformOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| 'value': 'fuchsia', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'fuchsia', |
| }, |
| ), |
| // Request 2. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.platformOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'android', |
| }, |
| ), |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.platformOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| 'value': 'iOS', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'iOS', |
| }, |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('o'); |
| await terminalHandler.processTerminalInput('O'); |
| |
| expect(terminalHandler.logger.statusText, contains('Switched operating system to fuchsia')); |
| expect(terminalHandler.logger.statusText, contains('Switched operating system to iOS')); |
| }); |
| |
| testWithoutContext('o,O - debugTogglePlatform with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| // Request 1. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.platformOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'iOS', |
| }, |
| ), |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.platformOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| 'value': 'fuchsia', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'fuchsia', |
| }, |
| ), |
| // Request 2. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.platformOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'android', |
| }, |
| ), |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.platformOverride', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| 'value': 'iOS', |
| }, |
| jsonResponse: <String, Object>{ |
| 'value': 'iOS', |
| }, |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('o'); |
| await terminalHandler.processTerminalInput('O'); |
| |
| expect(terminalHandler.logger.statusText, contains('Switched operating system to fuchsia')); |
| expect(terminalHandler.logger.statusText, contains('Switched operating system to iOS')); |
| }); |
| |
| testWithoutContext('o,O - debugTogglePlatform without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('o'); |
| await terminalHandler.processTerminalInput('O'); |
| }); |
| |
| testWithoutContext('p - debugToggleDebugPaintSizeEnabled', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugPaint', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('p'); |
| }); |
| |
| testWithoutContext('p - debugToggleDebugPaintSizeEnabled with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugPaint', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('p'); |
| }); |
| |
| testWithoutContext('p - debugToggleDebugPaintSizeEnabled without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('p'); |
| }); |
| |
| testWithoutContext('P - debugTogglePerformanceOverlayOverride', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.showPerformanceOverlay', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('P'); |
| }); |
| |
| testWithoutContext('P - debugTogglePerformanceOverlayOverride with web target is skipped ', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], web: true); |
| await terminalHandler.processTerminalInput('P'); |
| }); |
| |
| testWithoutContext('P - debugTogglePerformanceOverlayOverride without service protocol is skipped ', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('P'); |
| }); |
| |
| testWithoutContext('S - debugDumpSemanticsTreeInTraversalOrder', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpSemanticsTreeInTraversalOrder', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'SEMANTICS DATA', |
| }, |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('S'); |
| |
| expect(terminalHandler.logger.statusText, contains('SEMANTICS DATA')); |
| }); |
| |
| testWithoutContext('S - debugDumpSemanticsTreeInTraversalOrder with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpSemanticsTreeInTraversalOrder', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'SEMANTICS DATA', |
| }, |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('S'); |
| |
| expect(terminalHandler.logger.statusText, contains('SEMANTICS DATA')); |
| }); |
| |
| testWithoutContext('S - debugDumpSemanticsTreeInTraversalOrder without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('S'); |
| }); |
| |
| testWithoutContext('U - debugDumpSemanticsTreeInInverseHitTestOrder', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpSemanticsTreeInInverseHitTestOrder', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'SEMANTICS DATA', |
| }, |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('U'); |
| |
| expect(terminalHandler.logger.statusText, contains('SEMANTICS DATA')); |
| }); |
| |
| testWithoutContext('U - debugDumpSemanticsTreeInInverseHitTestOrder with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpSemanticsTreeInInverseHitTestOrder', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'SEMANTICS DATA', |
| }, |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('U'); |
| |
| expect(terminalHandler.logger.statusText, contains('SEMANTICS DATA')); |
| }); |
| |
| testWithoutContext('U - debugDumpSemanticsTreeInInverseHitTestOrder without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('U'); |
| }); |
| |
| testWithoutContext('t,T - debugDumpRenderTree', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpRenderTree', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'RENDER DATA 1', |
| }, |
| ), |
| // Request 2. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpRenderTree', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'RENDER DATA 2', |
| }, |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('t'); |
| await terminalHandler.processTerminalInput('T'); |
| |
| expect(terminalHandler.logger.statusText, contains('RENDER DATA 1')); |
| expect(terminalHandler.logger.statusText, contains('RENDER DATA 2')); |
| }); |
| |
| testWithoutContext('t,T - debugDumpRenderTree with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpRenderTree', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'RENDER DATA 1', |
| }, |
| ), |
| // Request 2. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpRenderTree', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'RENDER DATA 2', |
| }, |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('t'); |
| await terminalHandler.processTerminalInput('T'); |
| |
| expect(terminalHandler.logger.statusText, contains('RENDER DATA 1')); |
| expect(terminalHandler.logger.statusText, contains('RENDER DATA 2')); |
| }); |
| |
| testWithoutContext('t,T - debugDumpRenderTree without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('t'); |
| await terminalHandler.processTerminalInput('T'); |
| }); |
| |
| testWithoutContext('w,W - debugDumpApp', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpApp', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'WIDGET DATA 1', |
| }, |
| ), |
| // Request 2. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpApp', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'WIDGET DATA 2', |
| }, |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('w'); |
| await terminalHandler.processTerminalInput('W'); |
| |
| expect(terminalHandler.logger.statusText, contains('WIDGET DATA 1')); |
| expect(terminalHandler.logger.statusText, contains('WIDGET DATA 2')); |
| }); |
| |
| testWithoutContext('w,W - debugDumpApp with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpApp', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'WIDGET DATA 1', |
| }, |
| ), |
| // Request 2. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugDumpApp', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| jsonResponse: <String, Object>{ |
| 'data': 'WIDGET DATA 2', |
| }, |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('w'); |
| await terminalHandler.processTerminalInput('W'); |
| |
| expect(terminalHandler.logger.statusText, contains('WIDGET DATA 1')); |
| expect(terminalHandler.logger.statusText, contains('WIDGET DATA 2')); |
| }); |
| |
| testWithoutContext('v - launchDevToolsInBrowser', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[]); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| final FakeResidentDevtoolsHandler devtoolsHandler = runner.residentDevtoolsHandler as FakeResidentDevtoolsHandler; |
| |
| expect(devtoolsHandler.calledLaunchDevToolsInBrowser, isFalse); |
| await terminalHandler.processTerminalInput('v'); |
| expect(devtoolsHandler.calledLaunchDevToolsInBrowser, isTrue); |
| }); |
| |
| testWithoutContext('w,W - debugDumpApp without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('w'); |
| await terminalHandler.processTerminalInput('W'); |
| }); |
| |
| testWithoutContext('z,Z - debugToggleDebugCheckElevationsEnabled', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugCheckElevationsEnabled', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| // Request 2. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugCheckElevationsEnabled', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| ]); |
| await terminalHandler.processTerminalInput('z'); |
| await terminalHandler.processTerminalInput('Z'); |
| }); |
| |
| testWithoutContext('z,Z - debugToggleDebugCheckElevationsEnabled with web target', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugCheckElevationsEnabled', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| // Request 2. |
| listViews, |
| const FakeVmServiceRequest( |
| method: 'ext.flutter.debugCheckElevationsEnabled', |
| args: <String, Object>{ |
| 'isolateId': '1', |
| }, |
| ), |
| ], web: true); |
| await terminalHandler.processTerminalInput('z'); |
| await terminalHandler.processTerminalInput('Z'); |
| }); |
| |
| testWithoutContext('z,Z - debugToggleDebugCheckElevationsEnabled without service protocol is skipped', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsServiceProtocol: false); |
| await terminalHandler.processTerminalInput('z'); |
| await terminalHandler.processTerminalInput('Z'); |
| }); |
| |
| testWithoutContext('q,Q - exit', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[]); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| await terminalHandler.processTerminalInput('q'); |
| |
| expect(runner.calledExit, true); |
| runner.calledExit = false; |
| |
| await terminalHandler.processTerminalInput('Q'); |
| |
| expect(runner.calledExit, true); |
| }); |
| |
| testWithoutContext('r - hotReload unsupported', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsHotReload: false); |
| await terminalHandler.processTerminalInput('r'); |
| }); |
| |
| testWithoutContext('R - hotRestart unsupported', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], supportsRestart: false); |
| await terminalHandler.processTerminalInput('R'); |
| }); |
| |
| testWithoutContext('r - hotReload', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[]); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| |
| await terminalHandler.processTerminalInput('r'); |
| |
| expect(runner.calledReload, true); |
| expect(runner.calledRestart, false); |
| }); |
| |
| testWithoutContext('R - hotRestart', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[]); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| |
| await terminalHandler.processTerminalInput('R'); |
| |
| expect(runner.calledReload, false); |
| expect(runner.calledRestart, true); |
| }); |
| |
| testWithoutContext('r - hotReload with non-fatal error', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], reloadExitCode: 1); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| |
| await terminalHandler.processTerminalInput('r'); |
| |
| expect(runner.calledReload, true); |
| expect(runner.calledRestart, false); |
| expect(terminalHandler.logger.statusText, contains('Try again after fixing the above error(s).')); |
| }); |
| |
| testWithoutContext('R - hotRestart with non-fatal error', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], reloadExitCode: 1); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| |
| await terminalHandler.processTerminalInput('R'); |
| |
| expect(runner.calledReload, false); |
| expect(runner.calledRestart, true); |
| expect(terminalHandler.logger.statusText, contains('Try again after fixing the above error(s).')); |
| }); |
| |
| testWithoutContext('r - hotReload with fatal error', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], reloadExitCode: 1, fatalReloadError: true); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| |
| await expectLater(() => terminalHandler.processTerminalInput('r'), throwsToolExit()); |
| |
| expect(runner.calledReload, true); |
| expect(runner.calledRestart, false); |
| }); |
| |
| testWithoutContext('R - hotRestart with fatal error', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], reloadExitCode: 1, fatalReloadError: true); |
| final FakeResidentRunner runner = terminalHandler.residentRunner as FakeResidentRunner; |
| |
| await expectLater(() => terminalHandler.processTerminalInput('R'), throwsToolExit()); |
| |
| expect(runner.calledReload, false); |
| expect(runner.calledRestart, true); |
| }); |
| }); |
| |
| testWithoutContext('ResidentRunner clears the screen when it should', () async { |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], reloadExitCode: 1, fatalReloadError: true); |
| const String message = 'This should be cleared'; |
| |
| expect(terminalHandler.logger.statusText, equals('')); |
| terminalHandler.logger.printStatus(message); |
| expect(terminalHandler.logger.statusText, equals('$message\n')); // printStatus makes a newline |
| |
| await terminalHandler.processTerminalInput('c'); |
| expect(terminalHandler.logger.statusText, equals('')); |
| }); |
| |
| testWithoutContext('s, can take screenshot on debug device that supports screenshot', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'false', |
| }, |
| ), |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'true', |
| }, |
| ), |
| ], logger: logger, supportsScreenshot: true); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.statusText, contains('Screenshot written to flutter_01.png (0kB)')); |
| }); |
| |
| testWithoutContext('s, can take screenshot on debug device that does not support screenshot', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'false', |
| }, |
| ), |
| FakeVmServiceRequest( |
| method: '_flutter.screenshot', |
| args: <String, Object>{}, |
| jsonResponse: <String, Object>{ |
| 'screenshot': base64.encode(<int>[1, 2, 3, 4]), |
| }, |
| ), |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'true', |
| }, |
| ), |
| ], logger: logger, fileSystem: fileSystem); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.statusText, contains('Screenshot written to flutter_01.png (0kB)')); |
| expect(fileSystem.currentDirectory.childFile('flutter_01.png').readAsBytesSync(), <int>[1, 2, 3, 4]); |
| }); |
| |
| testWithoutContext('s, can take screenshot on debug web device that does not support screenshot', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ |
| listViews, |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'false', |
| }, |
| ), |
| FakeVmServiceRequest( |
| method: 'ext.dwds.screenshot', |
| args: <String, Object>{}, |
| jsonResponse: <String, Object>{ |
| 'data': base64.encode(<int>[1, 2, 3, 4]), |
| }, |
| ), |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'true', |
| }, |
| ), |
| ], logger: logger, web: true, fileSystem: fileSystem); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.statusText, contains('Screenshot written to flutter_01.png (0kB)')); |
| expect(fileSystem.currentDirectory.childFile('flutter_01.png').readAsBytesSync(), <int>[1, 2, 3, 4]); |
| }); |
| |
| testWithoutContext('s, can take screenshot on device that does not support service protocol', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler( |
| <FakeVmServiceRequest>[], |
| logger: logger, |
| supportsScreenshot: true, |
| supportsServiceProtocol: false, |
| fileSystem: fileSystem, |
| ); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.statusText, contains('Screenshot written to flutter_01.png (0kB)')); |
| expect(fileSystem.currentDirectory.childFile('flutter_01.png').readAsBytesSync(), <int>[1, 2, 3, 4]); |
| }); |
| |
| testWithoutContext('s, does not take a screenshot on a device that does not support screenshot or the service protocol', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler( |
| <FakeVmServiceRequest>[], |
| logger: logger, |
| supportsServiceProtocol: false, |
| fileSystem: fileSystem, |
| ); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.statusText, '\n'); |
| expect(fileSystem.currentDirectory.childFile('flutter_01.png'), isNot(exists)); |
| }); |
| |
| testWithoutContext('s, does not take a screenshot on a web device that does not support screenshot or the service protocol', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler( |
| <FakeVmServiceRequest>[], |
| logger: logger, |
| supportsServiceProtocol: false, |
| web: true, |
| fileSystem: fileSystem, |
| ); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.statusText, '\n'); |
| expect(fileSystem.currentDirectory.childFile('flutter_01.png'), isNot(exists)); |
| }); |
| |
| testWithoutContext('s, bails taking screenshot on debug device if debugAllowBanner throws RpcError', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler( |
| <FakeVmServiceRequest>[ |
| listViews, |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'false', |
| }, |
| // Failed response, |
| errorCode: RPCErrorCodes.kInternalError, |
| ), |
| ], |
| logger: logger, |
| fileSystem: fileSystem, |
| ); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.errorText, contains('Error')); |
| }); |
| |
| testWithoutContext('s, bails taking screenshot on debug device if flutter.screenshot throws RpcError, restoring banner', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler( |
| <FakeVmServiceRequest>[ |
| listViews, |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'false', |
| }, |
| ), |
| const FakeVmServiceRequest( |
| method: '_flutter.screenshot', |
| // Failed response, |
| errorCode: RPCErrorCodes.kInternalError, |
| ), |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'true', |
| }, |
| ), |
| ], |
| logger: logger, |
| fileSystem: fileSystem, |
| ); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.errorText, contains('Error')); |
| }); |
| |
| testWithoutContext('s, bails taking screenshot on debug device if dwds.screenshot throws RpcError, restoring banner', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler( |
| <FakeVmServiceRequest>[ |
| listViews, |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'false', |
| }, |
| ), |
| const FakeVmServiceRequest( |
| method: 'ext.dwds.screenshot', |
| // Failed response, |
| errorCode: RPCErrorCodes.kInternalError, |
| ), |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'true', |
| }, |
| ), |
| ], |
| logger: logger, |
| web: true, |
| fileSystem: fileSystem, |
| ); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.errorText, contains('Error')); |
| }); |
| |
| testWithoutContext('s, bails taking screenshot on debug device if debugAllowBanner during second request', () async { |
| final BufferLogger logger = BufferLogger.test(); |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final TerminalHandler terminalHandler = setUpTerminalHandler( |
| <FakeVmServiceRequest>[ |
| listViews, |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'false', |
| }, |
| ), |
| FakeVmServiceRequest( |
| method: 'ext.flutter.debugAllowBanner', |
| args: <String, Object?>{ |
| 'isolateId': fakeUnpausedIsolate.id, |
| 'enabled': 'true', |
| }, |
| // Failed response, |
| errorCode: RPCErrorCodes.kInternalError, |
| ), |
| ], |
| logger: logger, |
| supportsScreenshot: true, |
| fileSystem: fileSystem, |
| ); |
| |
| await terminalHandler.processTerminalInput('s'); |
| |
| expect(logger.errorText, contains('Error')); |
| }); |
| |
| testWithoutContext('pidfile creation', () { |
| final BufferLogger testLogger = BufferLogger.test(); |
| final Signals signals = _TestSignals(Signals.defaultExitSignals); |
| final Terminal terminal = Terminal.test(); |
| final MemoryFileSystem fs = MemoryFileSystem.test(); |
| final ProcessInfo processInfo = ProcessInfo.test(fs); |
| final FakeResidentRunner residentRunner = FakeResidentRunner( |
| FlutterDevice( |
| FakeDevice(), |
| buildInfo: BuildInfo.debug, |
| generator: FakeResidentCompiler(), |
| developmentShaderCompiler: const FakeShaderCompiler(), |
| ), |
| testLogger, |
| fs, |
| ); |
| residentRunner |
| ..supportsRestart = true |
| ..supportsServiceProtocol = true |
| ..stayResident = true; |
| |
| const String filename = 'test.pid'; |
| final TerminalHandler terminalHandler = TerminalHandler( |
| residentRunner, |
| logger: testLogger, |
| signals: signals, |
| terminal: terminal, |
| processInfo: processInfo, |
| reportReady: false, |
| pidFile: filename, |
| ); |
| |
| expect(fs.file(filename), isNot(exists)); |
| terminalHandler.setupTerminal(); |
| terminalHandler.registerSignalHandlers(); |
| expect(fs.file(filename), exists); |
| terminalHandler.stop(); |
| expect(fs.file(filename), isNot(exists)); |
| }); |
| } |
| |
| class FakeResidentRunner extends ResidentHandlers { |
| FakeResidentRunner(FlutterDevice device, this.logger, this.fileSystem) : flutterDevices = <FlutterDevice>[device]; |
| |
| bool calledDetach = false; |
| bool calledPrint = false; |
| bool calledExit = false; |
| bool calledPrintWithDetails = false; |
| bool calledReload = false; |
| bool calledRestart = false; |
| int reloadExitCode = 0; |
| bool fatalReloadError = false; |
| |
| @override |
| final Logger logger; |
| |
| @override |
| final FileSystem fileSystem; |
| |
| @override |
| final List<FlutterDevice> flutterDevices; |
| |
| @override |
| bool canHotReload = true; |
| |
| @override |
| bool hotMode = true; |
| |
| @override |
| bool isRunningDebug = true; |
| |
| @override |
| bool isRunningProfile = false; |
| |
| @override |
| bool isRunningRelease = false; |
| |
| @override |
| bool stayResident = true; |
| |
| @override |
| bool supportsRestart = true; |
| |
| @override |
| bool supportsServiceProtocol = true; |
| |
| @override |
| bool supportsWriteSkSL = true; |
| |
| @override |
| Future<void> cleanupAfterSignal() async { } |
| |
| @override |
| Future<void> detach() async { |
| calledDetach = true; |
| } |
| |
| @override |
| Future<void> exit() async { |
| calledExit = true; |
| } |
| |
| @override |
| void printHelp({required bool details}) { |
| if (details) { |
| calledPrintWithDetails = true; |
| } else { |
| calledPrint = true; |
| } |
| } |
| |
| @override |
| Future<void> runSourceGenerators() async { } |
| |
| @override |
| Future<OperationResult> restart({bool fullRestart = false, bool pause = false, String? reason}) async { |
| if (fullRestart && !supportsRestart) { |
| throw StateError('illegal restart'); |
| } |
| if (!fullRestart && !canHotReload) { |
| throw StateError('illegal reload'); |
| } |
| if (fullRestart) { |
| calledRestart = true; |
| } else { |
| calledReload = true; |
| } |
| return OperationResult(reloadExitCode, '', fatal: fatalReloadError); |
| } |
| |
| @override |
| ResidentDevtoolsHandler get residentDevtoolsHandler => _residentDevtoolsHandler; |
| final ResidentDevtoolsHandler _residentDevtoolsHandler = FakeResidentDevtoolsHandler(); |
| } |
| |
| class FakeResidentDevtoolsHandler extends Fake implements ResidentDevtoolsHandler { |
| bool calledLaunchDevToolsInBrowser = false; |
| |
| @override |
| bool launchDevToolsInBrowser({List<FlutterDevice?>? flutterDevices}) { |
| return calledLaunchDevToolsInBrowser = true; |
| } |
| } |
| |
| // 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 { |
| @override |
| bool isSupported() => true; |
| |
| @override |
| bool supportsScreenshot = false; |
| |
| @override |
| String get name => 'Fake Device'; |
| |
| @override |
| Future<void> takeScreenshot(File file) async { |
| if (!supportsScreenshot) { |
| throw StateError('illegal screenshot attempt'); |
| } |
| file.writeAsBytesSync(<int>[1, 2, 3, 4]); |
| } |
| |
| } |
| |
| TerminalHandler setUpTerminalHandler(List<FakeVmServiceRequest> requests, { |
| bool supportsRestart = true, |
| bool supportsServiceProtocol = true, |
| bool supportsHotReload = true, |
| bool web = false, |
| bool fatalReloadError = false, |
| bool supportsScreenshot = false, |
| int reloadExitCode = 0, |
| BuildMode buildMode = BuildMode.debug, |
| Logger? logger, |
| FileSystem? fileSystem, |
| }) { |
| final Logger testLogger = logger ?? BufferLogger.test(); |
| final Signals signals = Signals.test(); |
| final Terminal terminal = Terminal.test(); |
| final FileSystem localFileSystem = fileSystem ?? MemoryFileSystem.test(); |
| final ProcessInfo processInfo = ProcessInfo.test(MemoryFileSystem.test()); |
| final FlutterDevice device = FlutterDevice( |
| FakeDevice()..supportsScreenshot = supportsScreenshot, |
| buildInfo: BuildInfo(buildMode, '', treeShakeIcons: false), |
| generator: FakeResidentCompiler(), |
| developmentShaderCompiler: const FakeShaderCompiler(), |
| targetPlatform: web |
| ? TargetPlatform.web_javascript |
| : TargetPlatform.android_arm, |
| ); |
| device.vmService = FakeVmServiceHost(requests: requests).vmService; |
| final FakeResidentRunner residentRunner = FakeResidentRunner(device, testLogger, localFileSystem) |
| ..supportsServiceProtocol = supportsServiceProtocol |
| ..supportsRestart = supportsRestart |
| ..canHotReload = supportsHotReload |
| ..fatalReloadError = fatalReloadError |
| ..reloadExitCode = reloadExitCode; |
| |
| switch (buildMode) { |
| case BuildMode.debug: |
| residentRunner |
| ..isRunningDebug = true |
| ..isRunningProfile = false |
| ..isRunningRelease = false; |
| case BuildMode.profile: |
| residentRunner |
| ..isRunningDebug = false |
| ..isRunningProfile = true |
| ..isRunningRelease = false; |
| case BuildMode.release: |
| residentRunner |
| ..isRunningDebug = false |
| ..isRunningProfile = false |
| ..isRunningRelease = true; |
| case _: |
| // NOOP |
| } |
| return TerminalHandler( |
| residentRunner, |
| logger: testLogger, |
| signals: signals, |
| terminal: terminal, |
| processInfo: processInfo, |
| reportReady: false, |
| ); |
| } |
| |
| class FakeResidentCompiler extends Fake implements ResidentCompiler { } |
| |
| class TestRunner extends Fake implements ResidentRunner { |
| bool hasHelpBeenPrinted = false; |
| |
| @override |
| Future<void> cleanupAfterSignal() async { } |
| |
| @override |
| Future<void> cleanupAtFinish() async { } |
| |
| @override |
| void printHelp({ bool? details }) { |
| hasHelpBeenPrinted = true; |
| } |
| |
| @override |
| Future<int?> run({ |
| Completer<DebugConnectionInfo>? connectionInfoCompleter, |
| Completer<void>? appStartedCompleter, |
| bool enableDevTools = false, |
| String? route, |
| }) async => null; |
| |
| @override |
| Future<int?> attach({ |
| Completer<DebugConnectionInfo>? connectionInfoCompleter, |
| Completer<void>? appStartedCompleter, |
| bool allowExistingDdsInstance = false, |
| bool enableDevTools = false, |
| bool needsFullRestart = true, |
| }) async => null; |
| } |
| |
| class _TestSignals implements Signals { |
| _TestSignals(this.exitSignals); |
| |
| final List<ProcessSignal> exitSignals; |
| |
| final Map<ProcessSignal, Map<Object, SignalHandler>> _handlersTable = |
| <ProcessSignal, Map<Object, SignalHandler>>{}; |
| |
| @override |
| Object addHandler(ProcessSignal signal, SignalHandler handler) { |
| final Object token = Object(); |
| _handlersTable.putIfAbsent(signal, () => <Object, SignalHandler>{})[token] = handler; |
| return token; |
| } |
| |
| @override |
| Future<bool> removeHandler(ProcessSignal signal, Object token) async { |
| if (!_handlersTable.containsKey(signal)) { |
| return false; |
| } |
| if (!_handlersTable[signal]!.containsKey(token)) { |
| return false; |
| } |
| _handlersTable[signal]!.remove(token); |
| return true; |
| } |
| |
| @override |
| Stream<Object> get errors => _errors.stream; |
| final StreamController<Object> _errors = StreamController<Object>(); |
| } |
| |
| class FakeShaderCompiler implements DevelopmentShaderCompiler { |
| const FakeShaderCompiler(); |
| |
| @override |
| void configureCompiler( |
| TargetPlatform? platform, { |
| required ImpellerStatus impellerStatus, |
| }) { } |
| |
| @override |
| Future<DevFSContent> recompileShader(DevFSContent inputShader) { |
| throw UnimplementedError(); |
| } |
| } |