| // Copyright 2019 The Flutter Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. | |
| import 'dart:async'; | |
| import 'dart:convert'; | |
| import 'dart:io'; | |
| import 'package:devtools_app/devtools_app.dart'; | |
| import 'package:devtools_app_shared/service.dart'; | |
| import 'package:devtools_shared/devtools_shared.dart'; | |
| import 'package:flutter/foundation.dart'; | |
| import 'package:mockito/mockito.dart'; | |
| import 'package:vm_service/vm_service.dart'; | |
| import 'generated_mocks_factories.dart'; | |
| class FakeInspectorService extends Fake implements InspectorService { | |
| final pubRootDirectories = <String>{}; | |
| @override | |
| ObjectGroup createObjectGroup(String debugName) { | |
| return ObjectGroup(debugName, this); | |
| } | |
| @override | |
| Future<bool> isWidgetTreeReady() async { | |
| return false; | |
| } | |
| @override | |
| Future<List<String>?> getPubRootDirectories() { | |
| return Future.value(pubRootDirectories.toList()); | |
| } | |
| @override | |
| Future<void> addPubRootDirectories(List<String> rootDirectories) { | |
| pubRootDirectories.addAll(rootDirectories); | |
| return Future<void>.value(); | |
| } | |
| @override | |
| Future<void> removePubRootDirectories(List<String> rootDirectories) { | |
| pubRootDirectories.removeAll(rootDirectories); | |
| return Future<void>.value(); | |
| } | |
| @override | |
| bool get useDaemonApi => true; | |
| @override | |
| final clients = <InspectorServiceClient>{}; | |
| @override | |
| void addClient(InspectorServiceClient client) { | |
| clients.add(client); | |
| } | |
| @override | |
| void removeClient(InspectorServiceClient client) { | |
| clients.remove(client); | |
| } | |
| @override | |
| bool get hoverEvalModeEnabledByDefault => true; | |
| } | |
| class TestInspectorController extends Fake implements InspectorController { | |
| InspectorService service = FakeInspectorService(); | |
| @override | |
| ValueListenable<InspectorTreeNode?> get selectedNode => _selectedNode; | |
| final _selectedNode = ValueNotifier<InspectorTreeNode?>(null); | |
| @override | |
| RemoteDiagnosticsNode? get selectedDiagnostic => _selectedDiagnostic; | |
| RemoteDiagnosticsNode? _selectedDiagnostic; | |
| @override | |
| ValueListenable<WidgetTreeNodeProperties> get selectedNodeProperties => | |
| ValueNotifier<WidgetTreeNodeProperties>(( | |
| widgetProperties: [], | |
| renderProperties: [], | |
| layoutProperties: null, | |
| )); | |
| @override | |
| void setSelectedNode(InspectorTreeNode? newSelection) { | |
| _selectedNode.value = newSelection; | |
| } | |
| void setSelectedDiagnostic(RemoteDiagnosticsNode newSelection) { | |
| _selectedDiagnostic = newSelection; | |
| } | |
| @override | |
| InspectorService get inspectorService => service; | |
| } | |
| class FakeVM extends Fake implements VM { | |
| FakeVM(); | |
| @override | |
| Map<String, dynamic>? json = {'_FAKE_VM': true, '_currentRSS': 0}; | |
| } | |
| class TestCodeViewController extends CodeViewController { | |
| @override | |
| ProgramExplorerController get programExplorerController => | |
| _explorerController; | |
| final _explorerController = createMockProgramExplorerControllerWithDefaults(); | |
| } | |
| void mockWebVm(VM vm) { | |
| when(vm.targetCPU).thenReturn('Web'); | |
| when(vm.architectureBits).thenReturn(-1); | |
| when(vm.operatingSystem).thenReturn('macos'); | |
| } | |
| void mockConnectedApp( | |
| ConnectedApp connectedApp, { | |
| bool isFlutterApp = true, | |
| bool isProfileBuild = false, | |
| bool isWebApp = false, | |
| bool isDebuggableWebApp = true, | |
| String os = 'ios', | |
| String flutterVersion = '2.10.0', | |
| }) { | |
| assert(!(!isFlutterApp && isProfileBuild)); | |
| // Dart VM. | |
| when(connectedApp.isRunningOnDartVM).thenReturn(!isWebApp); | |
| // Flutter app. | |
| when(connectedApp.isFlutterAppNow).thenReturn(isFlutterApp); | |
| when(connectedApp.isFlutterApp).thenAnswer((_) => Future.value(isFlutterApp)); | |
| when( | |
| connectedApp.isFlutterNativeAppNow, | |
| ).thenReturn(isFlutterApp && !isWebApp); | |
| when( | |
| connectedApp.isDebuggableWebApp, | |
| ).thenReturn(isWebApp && isDebuggableWebApp); | |
| if (isFlutterApp) { | |
| when(connectedApp.flutterVersionNow).thenReturn( | |
| FlutterVersion.parse({ | |
| 'type': 'Success', | |
| 'frameworkVersion': flutterVersion, | |
| 'channel': 'unknown', | |
| 'repositoryUrl': 'unknown source', | |
| 'frameworkRevision': '74432fa91c8ffbc555ffc2701309e8729380a012', | |
| 'frameworkCommitDate': '2020-05-14 13:05:34 -0700', | |
| 'engineRevision': 'ae2222f47e788070c09020311b573542b9706a78', | |
| 'dartSdkVersion': '2.9.0 (build 2.9.0-8.0.dev d6fed1f624)', | |
| 'frameworkRevisionShort': '74432fa91c', | |
| 'engineRevisionShort': 'ae2222f47e', | |
| }), | |
| ); | |
| } else { | |
| when(connectedApp.flutterVersionNow).thenReturn(null); | |
| } | |
| // Flutter web app. | |
| when(connectedApp.isFlutterWebAppNow).thenReturn(isFlutterApp && isWebApp); | |
| // Web app. | |
| when(connectedApp.isDartWebApp).thenAnswer((_) => Future.value(isWebApp)); | |
| when(connectedApp.isDartWebAppNow).thenReturn(isWebApp); | |
| // CLI app. | |
| final isCliApp = !isFlutterApp && !isWebApp; | |
| when(connectedApp.isDartCliApp).thenAnswer((_) => Future.value(isCliApp)); | |
| when(connectedApp.isDartCliAppNow).thenReturn(isCliApp); | |
| // Run mode. | |
| when( | |
| connectedApp.isProfileBuild, | |
| ).thenAnswer((_) => Future.value(isProfileBuild)); | |
| when(connectedApp.isProfileBuildNow).thenReturn(isProfileBuild); | |
| when( | |
| connectedApp.isDebugFlutterAppNow, | |
| ).thenReturn(isFlutterApp && !isProfileBuild); | |
| // Operating system. | |
| when(connectedApp.operatingSystem).thenReturn(os); | |
| // Initialized. | |
| when(connectedApp.connectedAppInitialized).thenReturn(true); | |
| when(connectedApp.initialized).thenReturn(Completer()..complete(true)); | |
| } | |
| void mockFlutterVersion(ConnectedApp connectedApp, SemanticVersion version) { | |
| when( | |
| connectedApp.flutterVersionNow, | |
| ).thenReturn(FlutterVersion.parse({'frameworkVersion': '$version'})); | |
| when(connectedApp.connectedAppInitialized).thenReturn(true); | |
| } | |
| final mockGrammar = Grammar.fromJson( | |
| jsonDecode(''' | |
| { | |
| "name": "Dart", | |
| "fileTypes": [ | |
| "dart" | |
| ], | |
| "scopeName": "source.dart", | |
| "patterns": [], | |
| "repository": {} | |
| } | |
| '''), | |
| ); | |
| final mockScriptRef = ScriptRef( | |
| uri: 'package:gallery/main.dart', | |
| id: 'test-script-long-lines', | |
| ); | |
| final mockLargeScriptRef = ScriptRef( | |
| uri: 'package:front_end/src/fasta/kernel/body_builder.dart', | |
| id: 'test-large-script', | |
| ); | |
| final mockEmptyScriptRef = ScriptRef( | |
| uri: 'package:gallery/src/unknown.dart', | |
| id: 'mock-script-no-source', | |
| ); | |
| final mockScript = _loadScript('script.json'); | |
| final mockLargeScript = _loadScript('large_script.json'); | |
| final mockEmptyScript = Script( | |
| uri: 'package:gallery/src/unknown.dart', | |
| id: 'mock-script-no-source', | |
| ); | |
| Script? _loadScript(String scriptName) { | |
| final script = File('../devtools_test/lib/src/mocks/mock_data/$scriptName'); | |
| return Script.parse(jsonDecode(script.readAsStringSync())); | |
| } | |
| final mockSyntaxHighlighter = SyntaxHighlighter.withGrammar( | |
| grammar: mockGrammar, | |
| source: mockScript!.source, | |
| ); | |
| const coverageHitLines = <int>{1, 3, 4, 7}; | |
| const coverageMissLines = <int>{2, 5}; | |
| const executableLines = <int>{...coverageHitLines, ...coverageMissLines}; | |
| const profilerEntries = <int, ProfileReportEntry>{ | |
| 1: ProfileReportEntry(sampleCount: 5, line: 1, inclusive: 2, exclusive: 2), | |
| 3: ProfileReportEntry(sampleCount: 5, line: 3, inclusive: 1, exclusive: 1), | |
| 4: ProfileReportEntry(sampleCount: 5, line: 4, inclusive: 1, exclusive: 1), | |
| 7: ProfileReportEntry(sampleCount: 5, line: 7, inclusive: 1, exclusive: 1), | |
| }; | |
| final mockParsedScript = ParsedScript( | |
| script: mockScript!, | |
| highlighter: mockSyntaxHighlighter, | |
| executableLines: executableLines, | |
| sourceReport: ProcessedSourceReport( | |
| coverageHitLines: coverageHitLines, | |
| coverageMissedLines: coverageMissLines, | |
| profilerEntries: profilerEntries, | |
| ), | |
| ); | |
| final mockScriptRefs = [ | |
| ScriptRef(uri: 'zoo:animals/cats/meow.dart', id: 'fake/id/1'), | |
| ScriptRef(uri: 'zoo:animals/cats/purr.dart', id: 'fake/id/2'), | |
| ScriptRef(uri: 'zoo:animals/dogs/bark.dart', id: 'fake/id/3'), | |
| ScriptRef(uri: 'zoo:animals/dogs/growl.dart', id: 'fake/id/4'), | |
| ScriptRef(uri: 'zoo:animals/insects/caterpillar.dart', id: 'fake/id/5'), | |
| ScriptRef(uri: 'zoo:animals/insects/cicada.dart', id: 'fake/id/6'), | |
| ScriptRef(uri: 'kitchen:food/catering/party.dart', id: 'fake/id/7'), | |
| ScriptRef(uri: 'kitchen:food/carton/milk.dart', id: 'fake/id/8'), | |
| ScriptRef(uri: 'kitchen:food/milk/carton.dart', id: 'fake/id/9'), | |
| ScriptRef(uri: 'travel:adventure/cave_tours_europe.dart', id: 'fake/id/10'), | |
| ScriptRef(uri: 'travel:canada/banff.dart', id: 'fake/id/11'), | |
| ]; | |
| class MockOfflineDataController extends Mock implements OfflineDataController { | |
| @override | |
| ValueNotifier<bool> showingOfflineData = ValueNotifier<bool>(false); | |
| } |