Add feature flag scaffolding to support experiments restricted to a specific Flutter channel (#9440)
diff --git a/packages/devtools_app/lib/src/app.dart b/packages/devtools_app/lib/src/app.dart index b1c2538..43c72cd 100644 --- a/packages/devtools_app/lib/src/app.dart +++ b/packages/devtools_app/lib/src/app.dart
@@ -86,7 +86,7 @@ /// flutter route parameters. class DevToolsAppState extends State<DevToolsApp> with AutoDisposeMixin { List<Screen> get _screens { - if (FeatureFlags.devToolsExtensions) { + if (FeatureFlags.devToolsExtensions.isEnabled) { // TODO(https://github.com/flutter/devtools/issues/6273): stop special // casing the package:provider extension. final containsProviderExtension = extensionService @@ -177,7 +177,7 @@ }); } - if (FeatureFlags.devToolsExtensions) { + if (FeatureFlags.devToolsExtensions.isEnabled) { addAutoDisposeListener( extensionService.currentExtensions, clearRoutesAndSetState,
diff --git a/packages/devtools_app/lib/src/framework/framework_core.dart b/packages/devtools_app/lib/src/framework/framework_core.dart index d7c4ac5..f141b01 100644 --- a/packages/devtools_app/lib/src/framework/framework_core.dart +++ b/packages/devtools_app/lib/src/framework/framework_core.dart
@@ -84,7 +84,7 @@ // preferences have been initialized. await extensionService.initialize(); - if (FeatureFlags.memoryObserver) { + if (FeatureFlags.memoryObserver.isEnabled) { _memoryObserver.init(); } } @@ -99,7 +99,7 @@ preferences.dispose(); _themeManager?.dispose(); unawaited(dtdManager.dispose()); - if (FeatureFlags.memoryObserver) { + if (FeatureFlags.memoryObserver.isEnabled) { _memoryObserver.dispose(); } }
diff --git a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart index be2b160..823ad42 100644 --- a/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart +++ b/packages/devtools_app/lib/src/framework/scaffold/scaffold.dart
@@ -58,7 +58,7 @@ static List<Widget> defaultActions({Color? color}) => [ OpenSettingsAction(color: color), - if (FeatureFlags.devToolsExtensions && + if (FeatureFlags.devToolsExtensions.isEnabled && !DevToolsQueryParams.load().hideExtensions) ExtensionSettingsAction(color: color), ReportFeedbackButton(color: color),
diff --git a/packages/devtools_app/lib/src/framework/scaffold/settings_dialog.dart b/packages/devtools_app/lib/src/framework/scaffold/settings_dialog.dart index 675641e..b9250f7 100644 --- a/packages/devtools_app/lib/src/framework/scaffold/settings_dialog.dart +++ b/packages/devtools_app/lib/src/framework/scaffold/settings_dialog.dart
@@ -77,7 +77,7 @@ gaItem: gac.vmDeveloperMode, ), ), - if (FeatureFlags.wasmOptInSetting) ...[ + if (FeatureFlags.wasmOptInSetting.isEnabled) ...[ const SizedBox(height: largeSpacing), ...dialogSubHeader(theme, 'Experimental features'), Flexible(
diff --git a/packages/devtools_app/lib/src/screens/app_size/app_size_controller.dart b/packages/devtools_app/lib/src/screens/app_size/app_size_controller.dart index 574a1e9..ecc58a4 100644 --- a/packages/devtools_app/lib/src/screens/app_size/app_size_controller.dart +++ b/packages/devtools_app/lib/src/screens/app_size/app_size_controller.dart
@@ -772,7 +772,7 @@ @override void releaseMemory({bool partial = false}) { - if (FeatureFlags.memoryObserver) { + if (FeatureFlags.memoryObserver.isEnabled) { // This behavior is the same regardless of the value of `partial`. We can // implement a partial clearing if it becomes necessary. clear(AppSizeScreen.analysisTabKey);
diff --git a/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart b/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart index fceb7d3..aacc0ec 100644 --- a/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart +++ b/packages/devtools_app/lib/src/screens/debugger/debugger_controller.dart
@@ -575,7 +575,7 @@ ); } // Update the variables for the stack frame: - if (FeatureFlags.dapDebugging) { + if (FeatureFlags.dapDebugging.isEnabled) { serviceConnection.appState.setDapVariables( frame != null ? await _createDapVariablesForFrame(frame.frame) : [], );
diff --git a/packages/devtools_app/lib/src/screens/debugger/variables.dart b/packages/devtools_app/lib/src/screens/debugger/variables.dart index 3c0dde1..6eda6ad 100644 --- a/packages/devtools_app/lib/src/screens/debugger/variables.dart +++ b/packages/devtools_app/lib/src/screens/debugger/variables.dart
@@ -24,7 +24,7 @@ Widget build(BuildContext context) { // TODO(kenz): preserve expanded state of tree on switching frames and // on stepping. - if (FeatureFlags.dapDebugging) { + if (FeatureFlags.dapDebugging.isEnabled) { return TreeView<DapObjectNode>( dataRootsListenable: serviceConnection.appState.dapVariables, dataDisplayProvider: (variable, onPressed) {
diff --git a/packages/devtools_app/lib/src/screens/inspector_shared/inspector_controls.dart b/packages/devtools_app/lib/src/screens/inspector_shared/inspector_controls.dart index 29d36cd..d1f810a 100644 --- a/packages/devtools_app/lib/src/screens/inspector_shared/inspector_controls.dart +++ b/packages/devtools_app/lib/src/screens/inspector_shared/inspector_controls.dart
@@ -30,7 +30,8 @@ final activeButtonColor = Theme.of( context, ).colorScheme.activeToggleButtonColor; - final isInspectorV2 = controller != null && FeatureFlags.inspectorV2; + final isInspectorV2 = + controller != null && FeatureFlags.inspectorV2.isEnabled; return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [
diff --git a/packages/devtools_app/lib/src/screens/inspector_shared/inspector_screen.dart b/packages/devtools_app/lib/src/screens/inspector_shared/inspector_screen.dart index f44aa28..b8b7744 100644 --- a/packages/devtools_app/lib/src/screens/inspector_shared/inspector_screen.dart +++ b/packages/devtools_app/lib/src/screens/inspector_shared/inspector_screen.dart
@@ -46,7 +46,7 @@ late InspectorScreenController controller; bool get shouldShowInspectorV2 => - FeatureFlags.inspectorV2 && + FeatureFlags.inspectorV2.isEnabled && !preferences.inspector.legacyInspectorEnabled.value; @override
diff --git a/packages/devtools_app/lib/src/screens/inspector_shared/inspector_settings_dialog.dart b/packages/devtools_app/lib/src/screens/inspector_shared/inspector_settings_dialog.dart index 25a91a2..ebc3705 100644 --- a/packages/devtools_app/lib/src/screens/inspector_shared/inspector_settings_dialog.dart +++ b/packages/devtools_app/lib/src/screens/inspector_shared/inspector_settings_dialog.dart
@@ -65,7 +65,7 @@ const SizedBox(height: largeSpacing), // TODO(https://github.com/flutter/devtools/issues/7860): Clean-up // after Inspector V2 has been released. - if (FeatureFlags.inspectorV2) + if (FeatureFlags.inspectorV2.isEnabled) Flexible( child: CheckboxSetting( notifier:
diff --git a/packages/devtools_app/lib/src/screens/logging/logging_controller.dart b/packages/devtools_app/lib/src/screens/logging/logging_controller.dart index d7c3181..9563c10 100644 --- a/packages/devtools_app/lib/src/screens/logging/logging_controller.dart +++ b/packages/devtools_app/lib/src/screens/logging/logging_controller.dart
@@ -805,7 +805,7 @@ @override void releaseMemory({bool partial = false}) { - if (FeatureFlags.memoryObserver) { + if (FeatureFlags.memoryObserver.isEnabled) { if (partial) { // Trim logs from the front so that the oldest logs are removed. _updateData(data.sublist(data.length ~/ 2));
diff --git a/packages/devtools_app/lib/src/screens/memory/framework/memory_controller.dart b/packages/devtools_app/lib/src/screens/memory/framework/memory_controller.dart index 9a54884..3f2a8f1 100644 --- a/packages/devtools_app/lib/src/screens/memory/framework/memory_controller.dart +++ b/packages/devtools_app/lib/src/screens/memory/framework/memory_controller.dart
@@ -217,7 +217,7 @@ @override FutureOr<void> releaseMemory({bool partial = false}) async { - if (FeatureFlags.memoryObserver) { + if (FeatureFlags.memoryObserver.isEnabled) { diff.clearSnapshots(partial: partial); // Clear all allocation traces since the traces form a single tracing // profile.
diff --git a/packages/devtools_app/lib/src/screens/memory/panes/control/widgets/secondary_controls.dart b/packages/devtools_app/lib/src/screens/memory/panes/control/widgets/secondary_controls.dart index 79515d6..af539bd 100644 --- a/packages/devtools_app/lib/src/screens/memory/panes/control/widgets/secondary_controls.dart +++ b/packages/devtools_app/lib/src/screens/memory/panes/control/widgets/secondary_controls.dart
@@ -52,7 +52,7 @@ ), const SizedBox(width: denseSpacing), ], - if (FeatureFlags.memorySaveLoad) ...[ + if (FeatureFlags.memorySaveLoad.isEnabled) ...[ OpenSaveButtonGroup( screenId: ScreenMetaData.memory.id, onSave: (_) => onSave(),
diff --git a/packages/devtools_app/lib/src/screens/network/network_controller.dart b/packages/devtools_app/lib/src/screens/network/network_controller.dart index 309b62e..1547315 100644 --- a/packages/devtools_app/lib/src/screens/network/network_controller.dart +++ b/packages/devtools_app/lib/src/screens/network/network_controller.dart
@@ -515,7 +515,7 @@ @override FutureOr<void> releaseMemory({bool partial = false}) async { - if (FeatureFlags.memoryObserver) { + if (FeatureFlags.memoryObserver.isEnabled) { await clear(partial: partial); } }
diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart index 90fecb0..88f71a9 100644 --- a/packages/devtools_app/lib/src/screens/network/network_screen.dart +++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart
@@ -244,7 +244,7 @@ ), ), const SizedBox(width: denseSpacing), - if (FeatureFlags.networkSaveLoad) + if (FeatureFlags.networkSaveLoad.isEnabled) OpenSaveButtonGroup( screenId: ScreenMetaData.network.id, saveFormats: const [SaveFormat.devtools, SaveFormat.har],
diff --git a/packages/devtools_app/lib/src/screens/performance/performance_controller.dart b/packages/devtools_app/lib/src/screens/performance/performance_controller.dart index cfb4469..85424fe 100644 --- a/packages/devtools_app/lib/src/screens/performance/performance_controller.dart +++ b/packages/devtools_app/lib/src/screens/performance/performance_controller.dart
@@ -291,7 +291,7 @@ @override FutureOr<void> releaseMemory({bool partial = false}) async { - if (FeatureFlags.memoryObserver) { + if (FeatureFlags.memoryObserver.isEnabled) { await clearData(partial: partial, clearVmTimeline: !partial); } }
diff --git a/packages/devtools_app/lib/src/screens/profiler/profiler_screen_controller.dart b/packages/devtools_app/lib/src/screens/profiler/profiler_screen_controller.dart index b476800..af58b7a 100644 --- a/packages/devtools_app/lib/src/screens/profiler/profiler_screen_controller.dart +++ b/packages/devtools_app/lib/src/screens/profiler/profiler_screen_controller.dart
@@ -188,7 +188,7 @@ @override FutureOr<void> releaseMemory({bool partial = false}) async { - if (FeatureFlags.memoryObserver) { + if (FeatureFlags.memoryObserver.isEnabled) { // There is no way to partially release memory for this screen. await clear(); }
diff --git a/packages/devtools_app/lib/src/service/vm_service_wrapper.dart b/packages/devtools_app/lib/src/service/vm_service_wrapper.dart index 312d0a8..a49971f 100644 --- a/packages/devtools_app/lib/src/service/vm_service_wrapper.dart +++ b/packages/devtools_app/lib/src/service/vm_service_wrapper.dart
@@ -487,7 +487,7 @@ String command, { required Object? args, }) async { - if (!FeatureFlags.dapDebugging) return null; + if (!FeatureFlags.dapDebugging.isEnabled) return null; // Warn the user if there is no DDS connection. if (!_ddsSupported) {
diff --git a/packages/devtools_app/lib/src/shared/feature_flags.dart b/packages/devtools_app/lib/src/shared/feature_flags.dart index 8225c80..d885a3e 100644 --- a/packages/devtools_app/lib/src/shared/feature_flags.dart +++ b/packages/devtools_app/lib/src/shared/feature_flags.dart
@@ -2,6 +2,7 @@ // 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 'package:devtools_app_shared/service.dart'; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; @@ -36,84 +37,192 @@ @visibleForTesting bool get enableBeta => enableExperiments || !isExternalBuild; -const _kNetworkDisconnectExperience = bool.fromEnvironment( - 'network_disconnect_experience', - defaultValue: true, -); - /// A namespace for feature flags, which set the visibility of features under /// active development. /// /// When adding a new feature flag, the developer is responsible for adding it -/// to the [_allFlags] map for debugging purposes. +/// to the [_booleanFlags] or [_flutterChannelFlags] map for debugging +/// purposes. extension FeatureFlags on Never { /// Flag to enable the DevTools memory observer, which attempts to help users /// avoid OOM crashes. /// /// https://github.com/flutter/devtools/issues/7002 - static bool memoryObserver = true; + static final memoryObserver = BooleanFeatureFlag( + name: 'memoryObserver', + enabled: true, + ); /// Flag to enable save/load for the Memory screen. /// /// https://github.com/flutter/devtools/issues/8019 - static bool memorySaveLoad = enableExperiments; - - /// Flag to enable viewing offline data on the network screen when an app - /// disconnects. - /// - /// https://github.com/flutter/devtools/issues/3806 - static const networkDisconnectExperience = _kNetworkDisconnectExperience; + static final memorySaveLoad = BooleanFeatureFlag( + name: 'memorySaveLoad', + enabled: enableExperiments, + ); /// Flag to enable save/load for the Network screen. /// /// https://github.com/flutter/devtools/issues/4470 - static bool networkSaveLoad = true; + static final networkSaveLoad = BooleanFeatureFlag( + name: 'networkSaveLoad', + enabled: true, + ); /// Flag to enable DevTools extensions. /// /// TODO(https://github.com/flutter/devtools/issues/6443): remove this flag /// once extension support is added in g3. - static bool devToolsExtensions = isExternalBuild; + static final devToolsExtensions = BooleanFeatureFlag( + name: 'devToolsExtensions', + enabled: isExternalBuild, + ); /// Flag to enable debugging via DAP. /// /// https://github.com/flutter/devtools/issues/6056 - static bool dapDebugging = enableExperiments; + static final dapDebugging = BooleanFeatureFlag( + name: 'dapDebugging', + enabled: enableExperiments, + ); /// Flag to enable the new Inspector panel. /// /// https://github.com/flutter/devtools/issues/7854 - static bool inspectorV2 = true; + static final inspectorV2 = BooleanFeatureFlag( + name: 'inspectorV2', + enabled: true, + ); /// Flag to enable the DevTools setting to opt-in to WASM. /// /// https://github.com/flutter/devtools/issues/7856 - static bool wasmOptInSetting = true; + static final wasmOptInSetting = BooleanFeatureFlag( + name: 'wasmOptInSetting', + enabled: true, + ); /// Flag to enable refactors in the Flutter Property Editor sidebar. /// /// https://github.com/flutter/devtools/issues/9214 - static bool propertyEditorRefactors = true; + static final propertyEditorRefactors = BooleanFeatureFlag( + name: 'propertyEditorRefactors', + enabled: true, + ); - /// Stores a map of all the feature flags for debugging purposes. + /// A set of all the boolean feature flags for debugging purposes. /// - /// When adding a new flag, you are responsible for adding it to this map as - /// well. - static final _allFlags = <String, bool>{ - 'memoryObserver': memoryObserver, - 'memorySaveLoad': memorySaveLoad, - 'networkDisconnectExperience': networkDisconnectExperience, - 'networkSaveLoad': networkSaveLoad, - 'dapDebugging': dapDebugging, - 'inspectorV2': inspectorV2, - 'wasmOptInSetting': wasmOptInSetting, - 'propertyEditorRefactors': propertyEditorRefactors, + /// When adding a new boolean flag, you are responsible for adding it to this + /// map as well. + static final _booleanFlags = <BooleanFeatureFlag>{ + memoryObserver, + memorySaveLoad, + networkSaveLoad, + devToolsExtensions, + dapDebugging, + inspectorV2, + wasmOptInSetting, + propertyEditorRefactors, + }; + + /// A set of all the Flutter channel feature flags for debugging purposes. + /// + /// When adding a new Flutter channel flag, you are responsible for adding it + /// to this map as well. + static final _flutterChannelFlags = <FlutterChannelFeatureFlag>{ + // TODO(https://github.com/flutter/devtools/issues/9438): Add wasm flag. }; /// A helper to print the status of all the feature flags. - static void debugPrintFeatureFlags() { - for (final entry in _allFlags.entries) { - _log.config('${entry.key}: ${entry.value}'); + static void debugPrintFeatureFlags({ConnectedApp? connectedApp}) { + for (final entry in _booleanFlags) { + _log.config(entry.toString()); + } + + for (final entry in _flutterChannelFlags) { + var logLine = entry.toString(); + if (connectedApp != null) { + logLine += '(enabled: ${entry.isEnabled(connectedApp)})'; + } + _log.config(logLine); } } } + +/// A simple feature flag that is enabled or disabled by a boolean value. +class BooleanFeatureFlag { + BooleanFeatureFlag({required this.name, required bool enabled}) + : _enabled = enabled; + + /// The name of the feature. + final String name; + + bool _enabled; + + /// Whether the feature is enabled. + bool get isEnabled => _enabled; + + @override + String toString() => '$name: $isEnabled'; + + @visibleForTesting + void setEnabledForTests(bool enabled) { + _enabled = enabled; + } +} + +/// A feature flag that is enabled based on the Flutter channel of the +/// connected application. +/// +/// This flag will be enabled if the connected app's Flutter channel is less +/// than or equal to [flutterChannel]. For example, if [flutterChannel] is +/// [FlutterChannel.beta], this flag will be enabled for apps on the 'beta' and +/// 'dev' channels, but not for apps on the 'stable' channel. +/// +/// TODO(https://github.com/flutter/devtools/issues/9439): Restrict features +/// based on the user's Dart version instead of Flutter version to allow for +/// shared experiments across Dart and Flutter. +class FlutterChannelFeatureFlag { + const FlutterChannelFeatureFlag({ + required this.name, + required this.flutterChannel, + required bool enabledForDartApps, + required bool enabledForFlutterAppsFallback, + }) : _enabledForDartApps = enabledForDartApps, + _enabledForFlutterAppsFallback = enabledForFlutterAppsFallback; + + /// The name of the feature. + final String name; + + /// The maximum Flutter channel that this feature is enabled for. + final FlutterChannel flutterChannel; + + /// Whether the feature is enabled when the connected app is a pure Dart app. + final bool _enabledForDartApps; + + /// Whether the feature is enabled when the connected app is a Flutter app, + /// but we cannot determine the Flutter channel. + final bool _enabledForFlutterAppsFallback; + + /// Returns whether the feature is enabled based on the [connectedApp]'s + /// Flutter version. + bool isEnabled(ConnectedApp connectedApp) { + final isFlutterApp = connectedApp.isFlutterAppNow ?? false; + if (!isFlutterApp) { + return _enabledForDartApps; + } + final flutterVersion = connectedApp.flutterVersionNow?.version; + if (flutterVersion == null) return _enabledForFlutterAppsFallback; + + final currentChannel = FlutterVersion.identifyChannel( + flutterVersion, + channelStr: connectedApp.flutterVersionNow?.channel, + ); + if (currentChannel == null) return _enabledForFlutterAppsFallback; + + return currentChannel <= flutterChannel; + } + + @override + String toString() => '$name: <=${flutterChannel.name}'; +}
diff --git a/packages/devtools_app/lib/src/shared/framework/screen.dart b/packages/devtools_app/lib/src/shared/framework/screen.dart index 75344e2..fcacc56 100644 --- a/packages/devtools_app/lib/src/shared/framework/screen.dart +++ b/packages/devtools_app/lib/src/shared/framework/screen.dart
@@ -17,7 +17,6 @@ import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; -import '../feature_flags.dart'; import '../globals.dart'; import '../primitives/listenable.dart'; import '../ui/icons.dart'; @@ -25,6 +24,11 @@ final _log = Logger('screen.dart'); +const _kNetworkDisconnectExperience = bool.fromEnvironment( + 'network_disconnect_experience', + defaultValue: true, +); + enum ScreenMetaData { home( 'home', @@ -81,7 +85,7 @@ tutorialVideoTimestamp: '?t=547', requiresConnection: false, // ignore: avoid_redundant_argument_values, false positive - worksWithOfflineData: FeatureFlags.networkDisconnectExperience, + worksWithOfflineData: _kNetworkDisconnectExperience, ), logging( 'logging',
diff --git a/packages/devtools_app/lib/src/shared/preferences/preferences.dart b/packages/devtools_app/lib/src/shared/preferences/preferences.dart index cfc9230..c54e260 100644 --- a/packages/devtools_app/lib/src/shared/preferences/preferences.dart +++ b/packages/devtools_app/lib/src/shared/preferences/preferences.dart
@@ -118,7 +118,7 @@ // Get the current values and listen for and write back changes. await _initDarkMode(); await _initAdvancedDeveloperMode(); - if (FeatureFlags.wasmOptInSetting) { + if (FeatureFlags.wasmOptInSetting.isEnabled) { await _initWasmEnabled(); } await _initVerboseLogging();
diff --git a/packages/devtools_app/lib/src/shared/ui/utils.dart b/packages/devtools_app/lib/src/shared/ui/utils.dart index d46894c..bf82e99 100644 --- a/packages/devtools_app/lib/src/shared/ui/utils.dart +++ b/packages/devtools_app/lib/src/shared/ui/utils.dart
@@ -6,10 +6,10 @@ import 'dart:math'; import 'package:devtools_app_shared/ui.dart'; +import 'package:devtools_app_shared/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; -import '../primitives/enum_utils.dart'; import '../primitives/utils.dart'; /// Returns a [TextSpan] that only includes the first [length] characters of
diff --git a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_controller.dart b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_controller.dart index f3d1bb5..2be618e 100644 --- a/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_controller.dart +++ b/packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_controller.dart
@@ -223,7 +223,8 @@ CodeActionResult? refactorsResult; // TODO(https://github.com/flutter/devtools/issues/8652): Enable refactors // in the Property Editor by default. - if (editableArgsResult != null && FeatureFlags.propertyEditorRefactors) { + if (editableArgsResult != null && + FeatureFlags.propertyEditorRefactors.isEnabled) { // Fetch the refactors using the start of the editable arguments' range, // which corresponds to the widget constructor name. This ensures that the // refactors are always available, even when the cursor is within the
diff --git a/packages/devtools_app/test/framework/home_screen_test.dart b/packages/devtools_app/test/framework/home_screen_test.dart index 29774fb..0036d28 100644 --- a/packages/devtools_app/test/framework/home_screen_test.dart +++ b/packages/devtools_app/test/framework/home_screen_test.dart
@@ -83,12 +83,7 @@ fakeServiceConnection.serviceManager.vm.operatingSystem, ).thenReturn('android'); final app = fakeServiceConnection.serviceManager.connectedApp!; - mockConnectedApp( - app, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(app); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); }
diff --git a/packages/devtools_app/test/framework/observer/memory_observer_test.dart b/packages/devtools_app/test/framework/observer/memory_observer_test.dart index 2572d3b..fb2ec91 100644 --- a/packages/devtools_app/test/framework/observer/memory_observer_test.dart +++ b/packages/devtools_app/test/framework/observer/memory_observer_test.dart
@@ -37,7 +37,7 @@ } setUpAll(() { - FeatureFlags.memoryObserver = true; + FeatureFlags.memoryObserver.setEnabledForTests(true); }); setUp(() { @@ -58,7 +58,7 @@ }); tearDownAll(() { - FeatureFlags.memoryObserver = false; + FeatureFlags.memoryObserver.setEnabledForTests(false); }); test(
diff --git a/packages/devtools_app/test/framework/scaffold/about_dialog_test.dart b/packages/devtools_app/test/framework/scaffold/about_dialog_test.dart index 2b32b4c..16a96d6 100644 --- a/packages/devtools_app/test/framework/scaffold/about_dialog_test.dart +++ b/packages/devtools_app/test/framework/scaffold/about_dialog_test.dart
@@ -30,12 +30,7 @@ fakeServiceConnection.serviceManager.vm.operatingSystem, ).thenReturn('android'); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal( DevToolsEnvironmentParameters,
diff --git a/packages/devtools_app/test/framework/scaffold/scaffold_debugger_test.dart b/packages/devtools_app/test/framework/scaffold/scaffold_debugger_test.dart index 8d97604..381e3ab 100644 --- a/packages/devtools_app/test/framework/scaffold/scaffold_debugger_test.dart +++ b/packages/devtools_app/test/framework/scaffold/scaffold_debugger_test.dart
@@ -53,12 +53,7 @@ 'does not display floating debugger controls when debugger screen is showing', (WidgetTester tester) async { final connectedApp = MockConnectedApp(); - mockConnectedApp( - connectedApp, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(connectedApp); when(mockServiceManager.connectedAppInitialized).thenReturn(true); when(mockServiceManager.connectedApp).thenReturn(connectedApp); final mockDebuggerController = MockDebuggerController();
diff --git a/packages/devtools_app/test/framework/scaffold/scaffold_debugging_controls_test.dart b/packages/devtools_app/test/framework/scaffold/scaffold_debugging_controls_test.dart index b0003df..09692bd 100644 --- a/packages/devtools_app/test/framework/scaffold/scaffold_debugging_controls_test.dart +++ b/packages/devtools_app/test/framework/scaffold/scaffold_debugging_controls_test.dart
@@ -53,12 +53,7 @@ WidgetTester tester, ) async { final connectedApp = MockConnectedApp(); - mockConnectedApp( - connectedApp, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(connectedApp); when(mockServiceManager.connectedAppInitialized).thenReturn(true); when(mockServiceManager.connectedApp).thenReturn(connectedApp); when(mockServiceManager.isolateManager).thenReturn(FakeIsolateManager());
diff --git a/packages/devtools_app/test/framework/scaffold/scaffold_profile_test.dart b/packages/devtools_app/test/framework/scaffold/scaffold_profile_test.dart index e4c41bf..ea4fbc4 100644 --- a/packages/devtools_app/test/framework/scaffold/scaffold_profile_test.dart +++ b/packages/devtools_app/test/framework/scaffold/scaffold_profile_test.dart
@@ -52,12 +52,7 @@ WidgetTester tester, ) async { final connectedApp = MockConnectedApp(); - mockConnectedApp( - connectedApp, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: false, - ); + mockConnectedApp(connectedApp, isProfileBuild: true); when(mockServiceManager.connectedAppInitialized).thenReturn(true); when(mockServiceManager.connectedApp).thenReturn(connectedApp); final mockDebuggerController = MockDebuggerController();
diff --git a/packages/devtools_app/test/screens/cpu_profiler/profiler_screen_controller_test.dart b/packages/devtools_app/test/screens/cpu_profiler/profiler_screen_controller_test.dart index fe074ab..fca7471 100644 --- a/packages/devtools_app/test/screens/cpu_profiler/profiler_screen_controller_test.dart +++ b/packages/devtools_app/test/screens/cpu_profiler/profiler_screen_controller_test.dart
@@ -18,7 +18,7 @@ late ProfilerScreenController controller; setUp(() { - FeatureFlags.memoryObserver = true; + FeatureFlags.memoryObserver.setEnabledForTests(true); final fakeServiceConnection = FakeServiceConnectionManager( service: FakeServiceManager.createFakeService( cpuSamples: CpuSamples.parse(goldenCpuSamplesJson), @@ -63,7 +63,7 @@ }); test('releaseMemory', () async { - FeatureFlags.memoryObserver = true; + FeatureFlags.memoryObserver.setEnabledForTests(true); await controller.cpuProfilerController.loadAllSamples(); expect(controller.cpuProfilerController.dataNotifier.value, isNotNull); expect( @@ -75,7 +75,7 @@ controller.cpuProfilerController.dataNotifier.value, CpuProfilerController.baseStateCpuProfileData, ); - FeatureFlags.memoryObserver = false; + FeatureFlags.memoryObserver.setEnabledForTests(false); }); }); }
diff --git a/packages/devtools_app/test/screens/cpu_profiler/profiler_screen_test.dart b/packages/devtools_app/test/screens/cpu_profiler/profiler_screen_test.dart index 0d6914b..6a7d1ed 100644 --- a/packages/devtools_app/test/screens/cpu_profiler/profiler_screen_test.dart +++ b/packages/devtools_app/test/screens/cpu_profiler/profiler_screen_test.dart
@@ -77,9 +77,6 @@ (WidgetTester tester) async { mockConnectedApp( scene.fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: false, ); await pumpProfilerScreen(tester); verifyBaseState();
diff --git a/packages/devtools_app/test/screens/debugger/debugger_codeview_statistics_test.dart b/packages/devtools_app/test/screens/debugger/debugger_codeview_statistics_test.dart index 04a05a6..56e199f 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_codeview_statistics_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_codeview_statistics_test.dart
@@ -32,12 +32,7 @@ scriptsHistory = ScriptsHistory(); final app = fakeServiceConnection.serviceManager.connectedApp!; - mockConnectedApp( - app, - isFlutterApp: false, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(app); when( fakeServiceConnection.serviceManager.connectedApp!.isProfileBuildNow, ).thenReturn(false);
diff --git a/packages/devtools_app/test/screens/debugger/debugger_codeview_test.dart b/packages/devtools_app/test/screens/debugger/debugger_codeview_test.dart index 4078226..db88c2f 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_codeview_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_codeview_test.dart
@@ -38,12 +38,7 @@ codeViewController: codeViewController, ); scriptsHistory = ScriptsHistory(); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isProfileBuild: false, - isFlutterApp: true, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); setGlobal(ScriptManager, MockScriptManager());
diff --git a/packages/devtools_app/test/screens/debugger/debugger_screen_breakpoints_test.dart b/packages/devtools_app/test/screens/debugger/debugger_screen_breakpoints_test.dart index b314e61..7470497 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_screen_breakpoints_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_screen_breakpoints_test.dart
@@ -19,12 +19,7 @@ final mockBreakpointManager = MockBreakpointManager(); final fakeServiceConnection = FakeServiceConnectionManager(); final scriptManager = MockScriptManager(); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); setGlobal(ScriptManager, scriptManager);
diff --git a/packages/devtools_app/test/screens/debugger/debugger_screen_call_stack_test.dart b/packages/devtools_app/test/screens/debugger/debugger_screen_call_stack_test.dart index d7379bb..9d697fe 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_screen_call_stack_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_screen_call_stack_test.dart
@@ -24,12 +24,7 @@ setUp(() { fakeServiceConnection = FakeServiceConnectionManager(); scriptManager = MockScriptManager(); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isProfileBuild: false, - isFlutterApp: true, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); setGlobal(NotificationService, NotificationService());
diff --git a/packages/devtools_app/test/screens/debugger/debugger_screen_dap_variables_test.dart b/packages/devtools_app/test/screens/debugger/debugger_screen_dap_variables_test.dart index f43193e..4bd607d 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_screen_dap_variables_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_screen_dap_variables_test.dart
@@ -23,17 +23,12 @@ const windowSize = Size(2500, 1500); setUp(() { - FeatureFlags.dapDebugging = true; + FeatureFlags.dapDebugging.setEnabledForTests(true); vmService = createMockVmServiceWrapperWithDefaults(); fakeServiceConnection = FakeServiceConnectionManager(service: vmService); scriptManager = MockScriptManager(); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isProfileBuild: false, - isFlutterApp: true, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); setGlobal(ScriptManager, scriptManager);
diff --git a/packages/devtools_app/test/screens/debugger/debugger_screen_explorer_visibility_test.dart b/packages/devtools_app/test/screens/debugger/debugger_screen_explorer_visibility_test.dart index 4c7a922..29d92c2 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_screen_explorer_visibility_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_screen_explorer_visibility_test.dart
@@ -27,12 +27,7 @@ setUp(() { fakeServiceConnection = FakeServiceConnectionManager(); scriptManager = MockScriptManager(); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); setGlobal(NotificationService, NotificationService());
diff --git a/packages/devtools_app/test/screens/debugger/debugger_screen_paused_test.dart b/packages/devtools_app/test/screens/debugger/debugger_screen_paused_test.dart index e5d74c4..8507c46 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_screen_paused_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_screen_paused_test.dart
@@ -29,12 +29,7 @@ fakeServiceConnection = FakeServiceConnectionManager(); scriptManager = MockScriptManager(); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); setGlobal(ScriptManager, scriptManager);
diff --git a/packages/devtools_app/test/screens/debugger/debugger_screen_test.dart b/packages/devtools_app/test/screens/debugger/debugger_screen_test.dart index 61b3039..63bc094 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_screen_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_screen_test.dart
@@ -36,12 +36,7 @@ when( scriptManager.getScript(any), ).thenAnswer((_) => Future<Script>.value(testScript)); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); setGlobal(ScriptManager, scriptManager);
diff --git a/packages/devtools_app/test/screens/debugger/debugger_screen_variables_test.dart b/packages/devtools_app/test/screens/debugger/debugger_screen_variables_test.dart index 31145cf..2146435 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_screen_variables_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_screen_variables_test.dart
@@ -25,12 +25,7 @@ fakeServiceConnection = FakeServiceConnectionManager(); scriptManager = MockScriptManager(); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isProfileBuild: false, - isFlutterApp: true, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); setGlobal(ScriptManager, scriptManager);
diff --git a/packages/devtools_app/test/screens/debugger/debugger_scripts_test.dart b/packages/devtools_app/test/screens/debugger/debugger_scripts_test.dart index 548d95c..213c80f 100644 --- a/packages/devtools_app/test/screens/debugger/debugger_scripts_test.dart +++ b/packages/devtools_app/test/screens/debugger/debugger_scripts_test.dart
@@ -36,12 +36,7 @@ ); setGlobal(PreferencesController, PreferencesController()); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isProfileBuild: false, - isFlutterApp: true, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); } Future<void> pumpDebuggerScreen(
diff --git a/packages/devtools_app/test/screens/debugger/program_explorer_test.dart b/packages/devtools_app/test/screens/debugger/program_explorer_test.dart index eea09eb..189a7f5 100644 --- a/packages/devtools_app/test/screens/debugger/program_explorer_test.dart +++ b/packages/devtools_app/test/screens/debugger/program_explorer_test.dart
@@ -24,12 +24,7 @@ setUp(() { final fakeServiceConnection = FakeServiceConnectionManager(); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); mockProgramExplorerController = createMockProgramExplorerControllerWithDefaults(); setGlobal(IdeTheme, IdeTheme());
diff --git a/packages/devtools_app/test/screens/inspector/inspector_screen_test.dart b/packages/devtools_app/test/screens/inspector/inspector_screen_test.dart index be7223b..7dbc36f 100644 --- a/packages/devtools_app/test/screens/inspector/inspector_screen_test.dart +++ b/packages/devtools_app/test/screens/inspector/inspector_screen_test.dart
@@ -43,12 +43,7 @@ fakeServiceConnection = FakeServiceConnectionManager(); fakeExtensionManager = fakeServiceConnection.serviceManager.serviceExtensionManager; - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); when( fakeServiceConnection.errorBadgeManager.errorCountNotifier('inspector'), ).thenReturn(ValueNotifier<int>(0));
diff --git a/packages/devtools_app/test/screens/inspector/inspector_tree_test.dart b/packages/devtools_app/test/screens/inspector/inspector_tree_test.dart index 159e87c..17d1b12 100644 --- a/packages/devtools_app/test/screens/inspector/inspector_tree_test.dart +++ b/packages/devtools_app/test/screens/inspector/inspector_tree_test.dart
@@ -33,12 +33,7 @@ setGlobal(PreferencesController, PreferencesController()); setGlobal(NotificationService, NotificationService()); setGlobal(BreakpointManager, BreakpointManager()); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); inspectorController = InspectorController( inspectorTree: InspectorTreeController(),
diff --git a/packages/devtools_app/test/screens/inspector_v2/inspector_screen_test.dart b/packages/devtools_app/test/screens/inspector_v2/inspector_screen_test.dart index 303e1cf..813cc1e 100644 --- a/packages/devtools_app/test/screens/inspector_v2/inspector_screen_test.dart +++ b/packages/devtools_app/test/screens/inspector_v2/inspector_screen_test.dart
@@ -54,12 +54,7 @@ fakeServiceConnection = FakeServiceConnectionManager(); fakeExtensionManager = fakeServiceConnection.serviceManager.serviceExtensionManager; - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); when( fakeServiceConnection.errorBadgeManager.errorCountNotifier('inspector'), ).thenReturn(ValueNotifier<int>(0));
diff --git a/packages/devtools_app/test/screens/inspector_v2/inspector_tree_test.dart b/packages/devtools_app/test/screens/inspector_v2/inspector_tree_test.dart index f134241..5a7c896 100644 --- a/packages/devtools_app/test/screens/inspector_v2/inspector_tree_test.dart +++ b/packages/devtools_app/test/screens/inspector_v2/inspector_tree_test.dart
@@ -41,12 +41,7 @@ setGlobal(PreferencesController, PreferencesController()); setGlobal(NotificationService, NotificationService()); setGlobal(BreakpointManager, BreakpointManager()); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); inspectorController = InspectorController( inspectorTree: InspectorTreeController(),
diff --git a/packages/devtools_app/test/screens/logging/logging_controller_test.dart b/packages/devtools_app/test/screens/logging/logging_controller_test.dart index 35871ae..5dac954 100644 --- a/packages/devtools_app/test/screens/logging/logging_controller_test.dart +++ b/packages/devtools_app/test/screens/logging/logging_controller_test.dart
@@ -338,12 +338,12 @@ group('releaseMemory', () { setUp(() { - FeatureFlags.memoryObserver = true; + FeatureFlags.memoryObserver.setEnabledForTests(true); prepareTestLogs(); }); tearDown(() { - FeatureFlags.memoryObserver = false; + FeatureFlags.memoryObserver.setEnabledForTests(false); }); test('releaseMemory - full release', () {
diff --git a/packages/devtools_app/test/screens/memory/framework/memory_controller_test.dart b/packages/devtools_app/test/screens/memory/framework/memory_controller_test.dart index 3ae0e03..2fcc090 100644 --- a/packages/devtools_app/test/screens/memory/framework/memory_controller_test.dart +++ b/packages/devtools_app/test/screens/memory/framework/memory_controller_test.dart
@@ -72,12 +72,7 @@ setUp(() async { scene = MemoryDefaultScene(); await scene.setUp(classList: classList); - mockConnectedApp( - scene.fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(scene.fakeServiceConnection.serviceManager.connectedApp!); final mockScriptManager = MockScriptManager(); when( @@ -112,11 +107,11 @@ group('release memory', () { setUp(() { - FeatureFlags.memoryObserver = true; + FeatureFlags.memoryObserver.setEnabledForTests(true); }); tearDown(() { - FeatureFlags.memoryObserver = false; + FeatureFlags.memoryObserver.setEnabledForTests(false); }); testWidgetsWithWindowSize('full release', _windowSize, (
diff --git a/packages/devtools_app/test/screens/memory/tracing/tracing_view_test.dart b/packages/devtools_app/test/screens/memory/tracing/tracing_view_test.dart index 3d850ab..d7e8d8e 100644 --- a/packages/devtools_app/test/screens/memory/tracing/tracing_view_test.dart +++ b/packages/devtools_app/test/screens/memory/tracing/tracing_view_test.dart
@@ -78,9 +78,6 @@ await scene.setUp(classList: classList); mockConnectedApp( scene.fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, ); final mockScriptManager = MockScriptManager();
diff --git a/packages/devtools_app/test/screens/performance/controls/performance_controls_test.dart b/packages/devtools_app/test/screens/performance/controls/performance_controls_test.dart index 649f7da..b31e015 100644 --- a/packages/devtools_app/test/screens/performance/controls/performance_controls_test.dart +++ b/packages/devtools_app/test/screens/performance/controls/performance_controls_test.dart
@@ -40,12 +40,7 @@ mockServiceManager.serviceExtensionManager, ).thenReturn(FakeServiceExtensionManager()); final connectedApp = MockConnectedApp(); - mockConnectedApp( - connectedApp, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(connectedApp); when(mockServiceManager.connectedApp).thenReturn(connectedApp); setGlobal(ServiceConnectionManager, mockServiceConnection); mockPerformanceController = createMockPerformanceControllerWithDefaults(); @@ -85,12 +80,7 @@ testWidgetsWithWindowSize('builds for non flutter app', windowSize, ( WidgetTester tester, ) async { - mockConnectedApp( - mockServiceManager.connectedApp!, - isFlutterApp: false, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(mockServiceManager.connectedApp!, isFlutterApp: false); await pumpControls(tester); expect(find.byType(ExitOfflineButton), findsNothing);
diff --git a/packages/devtools_app/test/screens/performance/flutter_frames/flutter_frames_chart_test.dart b/packages/devtools_app/test/screens/performance/flutter_frames/flutter_frames_chart_test.dart index b0d63ca..0945d83 100644 --- a/packages/devtools_app/test/screens/performance/flutter_frames/flutter_frames_chart_test.dart +++ b/packages/devtools_app/test/screens/performance/flutter_frames/flutter_frames_chart_test.dart
@@ -40,12 +40,7 @@ group('FlutterFramesChart', () { setUp(() { final fakeServiceConnection = FakeServiceConnectionManager(); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(OfflineDataController, OfflineDataController()); setGlobal(IdeTheme, IdeTheme());
diff --git a/packages/devtools_app/test/screens/performance/frame_analysis/frame_analysis_test.dart b/packages/devtools_app/test/screens/performance/frame_analysis/frame_analysis_test.dart index a442e3c..085b5ca 100644 --- a/packages/devtools_app/test/screens/performance/frame_analysis/frame_analysis_test.dart +++ b/packages/devtools_app/test/screens/performance/frame_analysis/frame_analysis_test.dart
@@ -36,12 +36,7 @@ final fakeServiceConnection = FakeServiceConnectionManager(); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(NotificationService, NotificationService()); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); }); Future<void> pumpAnalysisView(
diff --git a/packages/devtools_app/test/screens/performance/frame_analysis/frame_hints_test.dart b/packages/devtools_app/test/screens/performance/frame_analysis/frame_hints_test.dart index 8a97003..b8a3a40 100644 --- a/packages/devtools_app/test/screens/performance/frame_analysis/frame_hints_test.dart +++ b/packages/devtools_app/test/screens/performance/frame_analysis/frame_hints_test.dart
@@ -47,12 +47,7 @@ final fakeServiceConnection = FakeServiceConnectionManager(); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(NotificationService, NotificationService()); - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); }); Future<void> pumpHints( @@ -359,9 +354,7 @@ ); mockConnectedApp( serviceConnection.serviceManager.connectedApp!, - isFlutterApp: true, isProfileBuild: true, - isWebApp: false, os: 'android', ); await pumpHints(tester, mockFrameAnalysis);
diff --git a/packages/devtools_app/test/screens/performance/performance_controller_test.dart b/packages/devtools_app/test/screens/performance/performance_controller_test.dart index 16bf1b0..b33f738 100644 --- a/packages/devtools_app/test/screens/performance/performance_controller_test.dart +++ b/packages/devtools_app/test/screens/performance/performance_controller_test.dart
@@ -29,12 +29,7 @@ final mockServiceManager = mockServiceConnection.serviceManager as MockServiceManager; final connectedApp = MockConnectedApp(); - mockConnectedApp( - connectedApp, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(connectedApp); when(mockServiceManager.connectedApp).thenReturn(connectedApp); when( mockServiceManager.connectedState,
diff --git a/packages/devtools_app/test/screens/performance/performance_screen_test.dart b/packages/devtools_app/test/screens/performance/performance_screen_test.dart index 8c93288..6f23218 100644 --- a/packages/devtools_app/test/screens/performance/performance_screen_test.dart +++ b/packages/devtools_app/test/screens/performance/performance_screen_test.dart
@@ -138,7 +138,6 @@ mockConnectedApp( fakeServiceConnection.serviceManager.connectedApp!, isFlutterApp: false, - isProfileBuild: false, isWebApp: true, ); await tester.pumpWidget( @@ -169,8 +168,6 @@ setEnableExperiments(); mockConnectedApp( fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, isWebApp: true, ); await tester.pumpWidget( @@ -202,8 +199,6 @@ mockConnectedApp( fakeServiceConnection.serviceManager.connectedApp!, isFlutterApp: false, - isProfileBuild: false, - isWebApp: false, ); await pumpPerformanceScreen(tester, runAsync: true); await tester.pumpAndSettle();
diff --git a/packages/devtools_app/test/screens/performance/tabbed_performance_view_test.dart b/packages/devtools_app/test/screens/performance/tabbed_performance_view_test.dart index 66239af..559e0b1 100644 --- a/packages/devtools_app/test/screens/performance/tabbed_performance_view_test.dart +++ b/packages/devtools_app/test/screens/performance/tabbed_performance_view_test.dart
@@ -31,12 +31,7 @@ ), ); final app = fakeServiceConnection.serviceManager.connectedApp!; - mockConnectedApp( - app, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: false, - ); + mockConnectedApp(app, isProfileBuild: true); when(app.flutterVersionNow).thenReturn( FlutterVersion.parse( (await fakeServiceConnection.serviceManager.flutterVersion).json!, @@ -214,12 +209,7 @@ await tester.runAsync(() async { await setUpServiceManagerWithTimeline(); final app = fakeServiceConnection.serviceManager.connectedApp!; - mockConnectedApp( - app, - isFlutterApp: false, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(app, isFlutterApp: false); when(app.flutterVersionNow).thenReturn(null); await pumpView(tester);
diff --git a/packages/devtools_app/test/service/connection_info_test.dart b/packages/devtools_app/test/service/connection_info_test.dart index a941f72..19c8a33 100644 --- a/packages/devtools_app/test/service/connection_info_test.dart +++ b/packages/devtools_app/test/service/connection_info_test.dart
@@ -34,12 +34,7 @@ fakeServiceConnection.serviceManager.vm.operatingSystem, ).thenReturn('android'); final app = fakeServiceConnection.serviceManager.connectedApp!; - mockConnectedApp( - app, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(app); setGlobal(ServiceConnectionManager, fakeServiceConnection); setGlobal(IdeTheme, IdeTheme()); } @@ -53,12 +48,7 @@ ) async { final app = fakeServiceConnection.serviceManager.connectedApp!; mockWebVm(fakeServiceConnection.serviceManager.vm); - mockConnectedApp( - app, - isFlutterApp: false, - isProfileBuild: false, - isWebApp: true, - ); + mockConnectedApp(app, isFlutterApp: false, isWebApp: true); await tester.pumpWidget(wrap(const ConnectedAppSummary())); expect(find.text('CPU / OS: '), findsOneWidget); @@ -81,12 +71,7 @@ when( fakeServiceConnection.serviceManager.vm.operatingSystem, ).thenReturn('macos'); - mockConnectedApp( - app, - isFlutterApp: false, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(app, isFlutterApp: false); await tester.pumpWidget(wrap(const ConnectedAppSummary())); expect(find.text('CPU / OS: '), findsOneWidget); @@ -107,12 +92,7 @@ windowSize, (WidgetTester tester) async { final app = fakeServiceConnection.serviceManager.connectedApp!; - mockConnectedApp( - app, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(app); await tester.pumpWidget(wrap(const ConnectedAppSummary())); expect(find.text('CPU / OS: '), findsOneWidget); @@ -139,12 +119,7 @@ windowSize, (WidgetTester tester) async { final app = fakeServiceConnection.serviceManager.connectedApp!; - mockConnectedApp( - app, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: false, - ); + mockConnectedApp(app, isProfileBuild: true); await tester.pumpWidget(wrap(const ConnectedAppSummary())); expect(find.text('CPU / OS: '), findsOneWidget); @@ -171,12 +146,7 @@ (WidgetTester tester) async { final app = fakeServiceConnection.serviceManager.connectedApp!; mockWebVm(fakeServiceConnection.serviceManager.vm); - mockConnectedApp( - app, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: true, - ); + mockConnectedApp(app, isWebApp: true); await tester.pumpWidget(wrap(const ConnectedAppSummary())); expect(find.text('CPU / OS: '), findsOneWidget); @@ -204,12 +174,7 @@ (WidgetTester tester) async { final app = fakeServiceConnection.serviceManager.connectedApp!; mockWebVm(fakeServiceConnection.serviceManager.vm); - mockConnectedApp( - app, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: true, - ); + mockConnectedApp(app, isProfileBuild: true, isWebApp: true); await tester.pumpWidget(wrap(const ConnectedAppSummary())); expect(find.text('CPU / OS: '), findsOneWidget);
diff --git a/packages/devtools_app/test/shared/charts/flame_chart_test.dart b/packages/devtools_app/test/shared/charts/flame_chart_test.dart index 00784b3..e250a77 100644 --- a/packages/devtools_app/test/shared/charts/flame_chart_test.dart +++ b/packages/devtools_app/test/shared/charts/flame_chart_test.dart
@@ -121,12 +121,7 @@ setGlobal(PreferencesController, PreferencesController()); final connectedApp = MockConnectedApp(); - mockConnectedApp( - connectedApp, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: false, - ); + mockConnectedApp(connectedApp, isProfileBuild: true); when(mockServiceManager.connectedApp).thenReturn(connectedApp); controller = CpuProfilerController();
diff --git a/packages/devtools_app/test/shared/primitives/enum_utils_test.dart b/packages/devtools_app/test/shared/primitives/enum_utils_test.dart index b31519f..a1e8d32 100644 --- a/packages/devtools_app/test/shared/primitives/enum_utils_test.dart +++ b/packages/devtools_app/test/shared/primitives/enum_utils_test.dart
@@ -2,7 +2,7 @@ // 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 'package:devtools_app/src/shared/primitives/enum_utils.dart'; +import 'package:devtools_app_shared/utils.dart'; import 'package:flutter_test/flutter_test.dart'; void main() {
diff --git a/packages/devtools_app/test/shared/primitives/feature_flags_test.dart b/packages/devtools_app/test/shared/primitives/feature_flags_test.dart index d00915e..bc5f69d 100644 --- a/packages/devtools_app/test/shared/primitives/feature_flags_test.dart +++ b/packages/devtools_app/test/shared/primitives/feature_flags_test.dart
@@ -2,23 +2,147 @@ // 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 'package:devtools_app/src/service/service_manager.dart'; import 'package:devtools_app/src/shared/feature_flags.dart'; import 'package:devtools_app/src/shared/globals.dart'; +import 'package:devtools_app_shared/service.dart'; +import 'package:devtools_app_shared/utils.dart'; +import 'package:devtools_test/devtools_test.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; void main() { test('constants have expected values', () { expect(enableExperiments, false); expect(enableBeta, false); expect(isExternalBuild, true); - expect(FeatureFlags.memoryObserver, true); - expect(FeatureFlags.memorySaveLoad, false); - expect(FeatureFlags.networkDisconnectExperience, true); - expect(FeatureFlags.networkSaveLoad, true); - expect(FeatureFlags.devToolsExtensions, isExternalBuild); - expect(FeatureFlags.dapDebugging, false); - expect(FeatureFlags.inspectorV2, true); - expect(FeatureFlags.wasmOptInSetting, true); - expect(FeatureFlags.propertyEditorRefactors, true); + expect(FeatureFlags.memoryObserver.isEnabled, true); + expect(FeatureFlags.memorySaveLoad.isEnabled, false); + expect(FeatureFlags.networkSaveLoad.isEnabled, true); + expect(FeatureFlags.devToolsExtensions.isEnabled, isExternalBuild); + expect(FeatureFlags.dapDebugging.isEnabled, false); + expect(FeatureFlags.inspectorV2.isEnabled, true); + expect(FeatureFlags.wasmOptInSetting.isEnabled, true); + expect(FeatureFlags.propertyEditorRefactors.isEnabled, true); + }); + + group('FlutterChannelFeatureFlag', () { + final connectedApp = MockConnectedApp(); + + late FlutterChannelFeatureFlag flag; + + setUp(() { + final mockServiceConnection = createMockServiceConnectionWithDefaults(); + final mockServiceManager = + mockServiceConnection.serviceManager as MockServiceManager; + when( + mockServiceManager.serviceExtensionManager, + ).thenReturn(FakeServiceExtensionManager()); + when(mockServiceManager.connectedApp).thenReturn(connectedApp); + setGlobal(ServiceConnectionManager, mockServiceConnection); + }); + + test('pure Dart app', () { + mockConnectedApp(connectedApp, isFlutterApp: false); + + flag = const FlutterChannelFeatureFlag( + name: 'test', + flutterChannel: FlutterChannel.dev, + enabledForDartApps: true, + enabledForFlutterAppsFallback: false, + ); + expect(flag.isEnabled(connectedApp), isTrue); + + flag = const FlutterChannelFeatureFlag( + name: 'test', + flutterChannel: FlutterChannel.dev, + enabledForDartApps: false, + enabledForFlutterAppsFallback: true, + ); + expect(flag.isEnabled(connectedApp), isFalse); + }); + + test('Flutter app on an unknown version', () { + mockConnectedApp(connectedApp, flutterVersion: 'unknown-version'); + + flag = const FlutterChannelFeatureFlag( + name: 'test', + flutterChannel: FlutterChannel.dev, + enabledForDartApps: false, + enabledForFlutterAppsFallback: true, + ); + expect(flag.isEnabled(connectedApp), isTrue); + + flag = const FlutterChannelFeatureFlag( + name: 'test', + flutterChannel: FlutterChannel.dev, + enabledForDartApps: true, + enabledForFlutterAppsFallback: false, + ); + expect(flag.isEnabled(connectedApp), isFalse); + }); + + group('Flutter app with version', () { + const stableVersion = '2.3.0'; + const betaVersion = '2.3.0-17.0.pre'; + const devVersion = '2.3.0-17.0.pre.355'; + + void enableFeatureFlagForChannel(FlutterChannel channel) { + flag = FlutterChannelFeatureFlag( + name: 'test', + flutterChannel: channel, + enabledForDartApps: false, + enabledForFlutterAppsFallback: false, + ); + } + + void expectEnabledForChannels({ + required bool enabledOnStable, + required bool enabledOnBeta, + required bool enabledOnDev, + }) { + // Flutter app using stable channel. + mockConnectedApp(connectedApp, flutterVersion: stableVersion); + expect(flag.isEnabled(connectedApp), equals(enabledOnStable)); + + // Flutter app using beta channel. + mockConnectedApp(connectedApp, flutterVersion: betaVersion); + expect(flag.isEnabled(connectedApp), equals(enabledOnBeta)); + + // Flutter app using dev channel. + mockConnectedApp(connectedApp, flutterVersion: devVersion); + expect(flag.isEnabled(connectedApp), equals(enabledOnDev)); + } + + test('enabled on dev', () { + enableFeatureFlagForChannel(FlutterChannel.dev); + + expectEnabledForChannels( + enabledOnStable: false, + enabledOnBeta: false, + enabledOnDev: true, + ); + }); + + test('enabled on beta', () { + enableFeatureFlagForChannel(FlutterChannel.beta); + + expectEnabledForChannels( + enabledOnStable: false, + enabledOnBeta: true, + enabledOnDev: true, + ); + }); + + test('enabled on stable', () { + enableFeatureFlagForChannel(FlutterChannel.stable); + + expectEnabledForChannels( + enabledOnStable: true, + enabledOnBeta: true, + enabledOnDev: true, + ); + }); + }); }); }
diff --git a/packages/devtools_app/test/shared/ui/vm_flag_widgets_test.dart b/packages/devtools_app/test/shared/ui/vm_flag_widgets_test.dart index e35bd05..65ad73d 100644 --- a/packages/devtools_app/test/shared/ui/vm_flag_widgets_test.dart +++ b/packages/devtools_app/test/shared/ui/vm_flag_widgets_test.dart
@@ -211,12 +211,7 @@ }); testWidgets('builds dialog', (WidgetTester tester) async { - mockConnectedApp( - fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(fakeServiceConnection.serviceManager.connectedApp!); await tester.pumpWidget(wrap(const VMFlagsDialog())); expect(find.richText('VM Flags'), findsOneWidget);
diff --git a/packages/devtools_app/test/standalone_ui/ide_shared/property_editor/property_editor_test.dart b/packages/devtools_app/test/standalone_ui/ide_shared/property_editor/property_editor_test.dart index 2a91132..adf33b1 100644 --- a/packages/devtools_app/test/standalone_ui/ide_shared/property_editor/property_editor_test.dart +++ b/packages/devtools_app/test/standalone_ui/ide_shared/property_editor/property_editor_test.dart
@@ -927,7 +927,7 @@ ); setUp(() { - FeatureFlags.propertyEditorRefactors = true; + FeatureFlags.propertyEditorRefactors.setEnabledForTests(true); refactorCount = 0; when(
diff --git a/packages/devtools_app/test/test_infra/scenes/cpu_profiler/default.dart b/packages/devtools_app/test/test_infra/scenes/cpu_profiler/default.dart index 3bced37..a4ff98d 100644 --- a/packages/devtools_app/test/test_infra/scenes/cpu_profiler/default.dart +++ b/packages/devtools_app/test/test_infra/scenes/cpu_profiler/default.dart
@@ -48,12 +48,7 @@ ), ); final app = fakeServiceConnection.serviceManager.connectedApp!; - mockConnectedApp( - app, - isFlutterApp: false, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(app, isFlutterApp: false); when( fakeServiceConnection.errorBadgeManager.errorCountNotifier('profiler'), ).thenReturn(ValueNotifier<int>(0));
diff --git a/packages/devtools_app/test/test_infra/scenes/memory/default.dart b/packages/devtools_app/test/test_infra/scenes/memory/default.dart index 96d4a6b..1827a0f 100644 --- a/packages/devtools_app/test/test_infra/scenes/memory/default.dart +++ b/packages/devtools_app/test/test_infra/scenes/memory/default.dart
@@ -131,12 +131,7 @@ ), ); final app = fakeServiceConnection.serviceManager.connectedApp!; - mockConnectedApp( - app, - isFlutterApp: true, - isProfileBuild: true, - isWebApp: false, - ); + mockConnectedApp(app, isProfileBuild: true); when( fakeServiceConnection.serviceManager.vm.operatingSystem, ).thenReturn('ios');
diff --git a/packages/devtools_app/test/test_infra/scenes/memory/diff_snapshot.dart b/packages/devtools_app/test/test_infra/scenes/memory/diff_snapshot.dart index 3702ba8..aa79a9d 100644 --- a/packages/devtools_app/test/test_infra/scenes/memory/diff_snapshot.dart +++ b/packages/devtools_app/test/test_infra/scenes/memory/diff_snapshot.dart
@@ -38,9 +38,7 @@ fakeServiceConnection = FakeServiceConnectionManager(); mockConnectedApp( fakeServiceConnection.serviceManager.connectedApp!, - isFlutterApp: true, isProfileBuild: true, - isWebApp: false, ); setGlobal(ServiceConnectionManager, fakeServiceConnection);
diff --git a/packages/devtools_app_shared/lib/src/service/flutter_version.dart b/packages/devtools_app_shared/lib/src/service/flutter_version.dart index 1ab54e8..f2819bb 100644 --- a/packages/devtools_app_shared/lib/src/service/flutter_version.dart +++ b/packages/devtools_app_shared/lib/src/service/flutter_version.dart
@@ -4,6 +4,8 @@ import 'package:devtools_shared/devtools_shared.dart'; +import '../../utils.dart'; + /// Flutter version service registered by Flutter Tools. /// /// We call this service to get version information about the Flutter framework, @@ -101,6 +103,54 @@ dartSdkVersion, ); + static final _stableVersionRegex = RegExp(r'^\d+\.\d+\.\d+$'); + static final _isNumericRegex = RegExp(r'\d'); + + /// Identifies the Flutter channel from a version string. + /// + /// This method will first attempt to use [channelStr] if it is provided. + /// Otherwise, it will fall back to parsing the channel from [versionStr]. + /// + /// This method will return `null` if the channel cannot be determined from + /// the provided information. + /// + /// Examples of versions that can be parsed: + /// * '2.3.0' -> [FlutterChannel.stable] + /// * '2.3.0-17.0.pre' -> [FlutterChannel.beta] + /// * '2.3.0-17.0.pre.355' -> [FlutterChannel.dev] + static FlutterChannel? identifyChannel( + String versionStr, { + String? channelStr, + }) { + // Check if channel string is valid. + if (channelStr != null) { + final channel = FlutterChannel.fromName(channelStr); + if (channel != null) return channel; + } + + // Check if version matches stable release format. + final sanitized = SemanticVersion.sanitizeVersionStr(versionStr); + if (_stableVersionRegex.hasMatch(sanitized)) return FlutterChannel.stable; + + // Check if version matches pre-release format. + const preReleaseIndicator = '.pre'; + final isValidPreRelease = sanitized.contains(preReleaseIndicator); + if (!isValidPreRelease) return null; + + // Check if version matches beta release format. + if (sanitized.endsWith(preReleaseIndicator)) return FlutterChannel.beta; + + // Check if version matches dev release format. + final versionParts = sanitized.split('$preReleaseIndicator.'); + final suffix = versionParts.last; + if (versionParts.length == 2 && _isNumericRegex.hasMatch(suffix)) { + return FlutterChannel.dev; + } + + // Matches no known release format, return null. + return null; + } + static SemanticVersion? _parseDartVersion(String? versionString) { if (versionString == null) return null; @@ -121,3 +171,18 @@ return SemanticVersion.parse(rawVersion); } } + +/// An enum representing the different Flutter channels. +enum FlutterChannel with EnumIndexOrdering { + dev, + beta, + stable; + + static FlutterChannel? fromName(String? name) { + try { + return FlutterChannel.values.byName(name ?? ''); + } catch (_) { + return null; + } + } +}
diff --git a/packages/devtools_app/lib/src/shared/primitives/enum_utils.dart b/packages/devtools_app_shared/lib/src/utils/enum_utils.dart similarity index 100% rename from packages/devtools_app/lib/src/shared/primitives/enum_utils.dart rename to packages/devtools_app_shared/lib/src/utils/enum_utils.dart
diff --git a/packages/devtools_app_shared/lib/utils.dart b/packages/devtools_app_shared/lib/utils.dart index 78fa6b8..3b9957d 100644 --- a/packages/devtools_app_shared/lib/utils.dart +++ b/packages/devtools_app_shared/lib/utils.dart
@@ -3,6 +3,7 @@ // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. export 'src/utils/auto_dispose.dart'; +export 'src/utils/enum_utils.dart'; export 'src/utils/globals.dart'; export 'src/utils/list.dart'; export 'src/utils/url/url.dart';
diff --git a/packages/devtools_app_shared/test/service/flutter_version_test.dart b/packages/devtools_app_shared/test/service/flutter_version_test.dart index 3e38f08..a1904d6 100644 --- a/packages/devtools_app_shared/test/service/flutter_version_test.dart +++ b/packages/devtools_app_shared/test/service/flutter_version_test.dart
@@ -69,6 +69,129 @@ expect(flutterVersion.patch, equals(0)); }); + group('identifies correct Flutter channel', () { + test('uses channel string if it exists', () { + expect( + FlutterVersion.identifyChannel('ignored-version', + channelStr: 'dev'), + equals(FlutterChannel.dev)); + + expect( + FlutterVersion.identifyChannel('ignored-version', + channelStr: 'beta'), + equals(FlutterChannel.beta)); + + expect( + FlutterVersion.identifyChannel('ignored-version', + channelStr: 'stable'), + equals(FlutterChannel.stable)); + }); + + test('identifies channel from version string', () { + expect(FlutterVersion.identifyChannel('2.3.0-17.0.pre.355'), + equals(FlutterChannel.dev)); + + expect(FlutterVersion.identifyChannel('2.3.0-17.0.pre-355'), + equals(FlutterChannel.dev)); + + expect(FlutterVersion.identifyChannel('2.3.0-17.0.pre'), + equals(FlutterChannel.beta)); + + expect(FlutterVersion.identifyChannel('2.3.0'), + equals(FlutterChannel.stable)); + + expect(FlutterVersion.identifyChannel('bad-version'), isNull); + + expect(FlutterVersion.identifyChannel('1.10.11-pre42'), isNull); + + expect(FlutterVersion.identifyChannel('2.3.0-17'), isNull); + }); + }); + + group('Flutter channel', () { + test('channel comparison', () { + // FlutterChannel.dev comparison: + // - compare to itself: + expect(FlutterChannel.dev == FlutterChannel.dev, isTrue); + expect(FlutterChannel.dev != FlutterChannel.dev, isFalse); + expect(FlutterChannel.dev < FlutterChannel.dev, isFalse); + expect(FlutterChannel.dev <= FlutterChannel.dev, isTrue); + expect(FlutterChannel.dev > FlutterChannel.dev, isFalse); + expect(FlutterChannel.dev >= FlutterChannel.dev, isTrue); + // - compare to beta: + expect(FlutterChannel.dev == FlutterChannel.beta, isFalse); + expect(FlutterChannel.dev != FlutterChannel.beta, isTrue); + expect(FlutterChannel.dev < FlutterChannel.beta, isTrue); + expect(FlutterChannel.dev <= FlutterChannel.beta, isTrue); + expect(FlutterChannel.dev > FlutterChannel.beta, isFalse); + expect(FlutterChannel.dev >= FlutterChannel.beta, isFalse); + // - compare to stable: + expect(FlutterChannel.dev == FlutterChannel.stable, isFalse); + expect(FlutterChannel.dev != FlutterChannel.stable, isTrue); + expect(FlutterChannel.dev < FlutterChannel.stable, isTrue); + expect(FlutterChannel.dev <= FlutterChannel.stable, isTrue); + expect(FlutterChannel.dev > FlutterChannel.stable, isFalse); + expect(FlutterChannel.dev >= FlutterChannel.stable, isFalse); + + // FlutterChannel.beta comparison: + // - compare to dev: + expect(FlutterChannel.beta == FlutterChannel.dev, isFalse); + expect(FlutterChannel.beta != FlutterChannel.dev, isTrue); + expect(FlutterChannel.beta < FlutterChannel.dev, isFalse); + expect(FlutterChannel.beta <= FlutterChannel.dev, isFalse); + expect(FlutterChannel.beta > FlutterChannel.dev, isTrue); + expect(FlutterChannel.beta >= FlutterChannel.dev, isTrue); + // - compare to itself: + expect(FlutterChannel.beta == FlutterChannel.beta, isTrue); + expect(FlutterChannel.beta != FlutterChannel.beta, isFalse); + expect(FlutterChannel.beta < FlutterChannel.beta, isFalse); + expect(FlutterChannel.beta <= FlutterChannel.beta, isTrue); + expect(FlutterChannel.beta > FlutterChannel.beta, isFalse); + expect(FlutterChannel.beta >= FlutterChannel.beta, isTrue); + // - compare to stable: + expect(FlutterChannel.beta == FlutterChannel.stable, isFalse); + expect(FlutterChannel.beta != FlutterChannel.stable, isTrue); + expect(FlutterChannel.beta < FlutterChannel.stable, isTrue); + expect(FlutterChannel.beta <= FlutterChannel.stable, isTrue); + expect(FlutterChannel.beta > FlutterChannel.stable, isFalse); + expect(FlutterChannel.beta >= FlutterChannel.stable, isFalse); + + // FlutterChannel.stable comparison: + // - compare to dev: + expect(FlutterChannel.stable == FlutterChannel.dev, isFalse); + expect(FlutterChannel.stable != FlutterChannel.dev, isTrue); + expect(FlutterChannel.stable < FlutterChannel.dev, isFalse); + expect(FlutterChannel.stable <= FlutterChannel.dev, isFalse); + expect(FlutterChannel.stable > FlutterChannel.dev, isTrue); + expect(FlutterChannel.stable >= FlutterChannel.dev, isTrue); + // - compare to beta: + expect(FlutterChannel.stable == FlutterChannel.beta, isFalse); + expect(FlutterChannel.stable != FlutterChannel.beta, isTrue); + expect(FlutterChannel.stable < FlutterChannel.beta, isFalse); + expect(FlutterChannel.stable <= FlutterChannel.beta, isFalse); + expect(FlutterChannel.stable > FlutterChannel.beta, isTrue); + expect(FlutterChannel.stable >= FlutterChannel.beta, isTrue); + // - compare to itself: + expect(FlutterChannel.stable == FlutterChannel.stable, isTrue); + expect(FlutterChannel.stable != FlutterChannel.stable, isFalse); + expect(FlutterChannel.stable < FlutterChannel.stable, isFalse); + expect(FlutterChannel.stable <= FlutterChannel.stable, isTrue); + expect(FlutterChannel.stable > FlutterChannel.stable, isFalse); + expect(FlutterChannel.stable >= FlutterChannel.stable, isTrue); + }); + + test('fromName factory', () { + expect(FlutterChannel.fromName('dev'), FlutterChannel.dev); + expect(FlutterChannel.fromName('beta'), FlutterChannel.beta); + expect(FlutterChannel.fromName('stable'), FlutterChannel.stable); + + expect(FlutterChannel.fromName('DEV'), isNull); + expect(FlutterChannel.fromName('unknown'), isNull); + expect(FlutterChannel.fromName(''), isNull); + expect(FlutterChannel.fromName(null), isNull); + }); + }); + test('parses dart version correctly', () { var flutterVersion = FlutterVersion.parse({ 'frameworkVersion': '2.8.0',
diff --git a/packages/devtools_shared/lib/src/utils/semantic_version.dart b/packages/devtools_shared/lib/src/utils/semantic_version.dart index 98d9644..3e8046f 100644 --- a/packages/devtools_shared/lib/src/utils/semantic_version.dart +++ b/packages/devtools_shared/lib/src/utils/semantic_version.dart
@@ -18,27 +18,8 @@ factory SemanticVersion.parse(String? versionString) { if (versionString == null) return SemanticVersion(); - // Remove any build metadata, denoted by a '+' character and whatever - // follows. - final buildMetadataIndex = versionString.indexOf('+'); - if (buildMetadataIndex != -1) { - versionString = versionString.substring(0, buildMetadataIndex); - } + final version = sanitizeVersionStr(versionString); - // [versionString] is expected to be of the form for VM.version, Dart, and - // Flutter, respectively: - // 2.15.0-233.0.dev (dev) (Mon Oct 18 14:06:26 2021 -0700) on "ios_x64" - // 2.15.0-178.1.beta - // 2.6.0-12.0.pre.443 - // 2.6.0-12.0.pre-443 - // - // First canonicalize the version string to convert any prerelease suffix - // with a "-" to a prerelease suffix with a ".". - final canonicalized = _canonicalizeVersion(versionString); - // Then split on the spaces to the version, and then on the dash char to - // separate the main semantic version from the pre release version. - final splitOnSpaces = canonicalized.split(' '); - final version = splitOnSpaces.first; final splitOnDash = version.split('-'); assert(splitOnDash.length <= 2, 'version: $version'); @@ -119,6 +100,33 @@ int? preReleaseMinor; + /// Sanitizes a version string so that it can be parsed as a + /// [SemanticVersion]. + /// + /// This method will remove build metadata and other trailing text from the + /// version string. For example: + /// + /// * '2.15.0-233.0.dev (dev) (Mon Oct 18 14:06:26 2021 -0700) on "ios_x64"' -> '2.15.0-233.0.dev' + /// * '2.15.0-178.1.beta' -> '2.15.0-178.1.beta' + /// * '2.6.0-12.0.pre.443' -> '2.6.0-12.0.pre.443' + /// * '3.0.0+123' -> '3.0.0' + static String sanitizeVersionStr(String versionString) { + // Remove any build metadata, denoted by a '+' character and whatever + // follows. + final buildMetadataIndex = versionString.indexOf('+'); + if (buildMetadataIndex != -1) { + versionString = versionString.substring(0, buildMetadataIndex); + } + // Canonicalize the version string to convert any prerelease suffix with a + // "-" to a prerelease suffix with a ".". + final canonicalized = _canonicalizeVersion(versionString); + // Then split on the spaces to the version, and then on the dash char to + // separate the main semantic version from the pre release version. + final splitOnSpaces = canonicalized.split(' '); + final version = splitOnSpaces.first; + return version; + } + static final _nonStandardPreReleaseVersionRegex = RegExp(r'(\.pre)-(\d+)$'); /// Canonicalizes a [semanticVersion] with a prerelease version suffix to use
diff --git a/packages/devtools_test/lib/src/mocks/fake_service_manager.dart b/packages/devtools_test/lib/src/mocks/fake_service_manager.dart index 206eb16..35efaa8 100644 --- a/packages/devtools_test/lib/src/mocks/fake_service_manager.dart +++ b/packages/devtools_test/lib/src/mocks/fake_service_manager.dart
@@ -102,12 +102,7 @@ _isolateManager = FakeIsolateManager(rootLibrary: rootLibrary) { this.service = service ?? createFakeService(); serviceUri = this.service!.wsUri; - mockConnectedApp( - connectedApp!, - isFlutterApp: true, - isProfileBuild: false, - isWebApp: false, - ); + mockConnectedApp(connectedApp!); setConnectedState(hasConnection); when(vm.operatingSystem).thenReturn('macos');
diff --git a/packages/devtools_test/lib/src/mocks/mocks.dart b/packages/devtools_test/lib/src/mocks/mocks.dart index acc9c15..d2f2b10 100644 --- a/packages/devtools_test/lib/src/mocks/mocks.dart +++ b/packages/devtools_test/lib/src/mocks/mocks.dart
@@ -143,10 +143,11 @@ void mockConnectedApp( ConnectedApp connectedApp, { - required bool isFlutterApp, - required bool isProfileBuild, - required bool isWebApp, + bool isFlutterApp = true, + bool isProfileBuild = false, + bool isWebApp = false, String os = 'ios', + String flutterVersion = '2.10.0', }) { assert(!(!isFlutterApp && isProfileBuild)); @@ -163,7 +164,7 @@ when(connectedApp.flutterVersionNow).thenReturn( FlutterVersion.parse({ 'type': 'Success', - 'frameworkVersion': '2.10.0', + 'frameworkVersion': flutterVersion, 'channel': 'unknown', 'repositoryUrl': 'unknown source', 'frameworkRevision': '74432fa91c8ffbc555ffc2701309e8729380a012',