diff --git a/analysis_options.yaml b/analysis_options.yaml index b6c61e1fe0a..f8bf98bf496 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -163,11 +163,12 @@ dart_code_metrics: # devtools_app/. # TODO(https://github.com/flutter/devtools/issues/9906) remove these # excludes as findings are resolved. - - integration_test/** - # Investigate internal usages of inspector_controller before removing. + # Investigate internal usages of inspector logic before removing. - lib/src/screens/inspector/**_controller.dart + - lib/src/shared/diagnostics/inspector_service.dart + - lib/src/shared/diagnostics/diagnostics_node.dart + - lib/src/service/** - - lib/src/shared/** - test/** rules: # - arguments-ordering Too strict diff --git a/packages/devtools_app/benchmark/devtools_benchmarks_test.dart b/packages/devtools_app/benchmark/devtools_benchmarks_test.dart index 15cf0a656d1..6b64940f19b 100644 --- a/packages/devtools_app/benchmark/devtools_benchmarks_test.dart +++ b/packages/devtools_app/benchmark/devtools_benchmarks_test.dart @@ -5,10 +5,10 @@ // Note: this test was modeled after the example test from Flutter Gallery: // https://github.com/flutter/gallery/blob/master/test_benchmarks/benchmarks_test.dart -import 'dart:convert' show JsonEncoder; import 'dart:io'; import 'package:collection/collection.dart'; +import 'package:devtools_app/src/shared/primitives/utils.dart'; import 'package:devtools_test/helpers.dart'; import 'package:test/test.dart'; import 'package:web_benchmarks/metrics.dart'; @@ -92,10 +92,7 @@ Future _runBenchmarks({bool useWasm = false}) async { stdout.writeln('Web benchmark tests finished.'); - expect( - const JsonEncoder.withIndent(' ').convert(taskResult.toJson()), - isA(), - ); + expect(prettyPrintJson(taskResult.toJson()), isA()); expect(taskResult.scores.keys, hasLength(DevToolsBenchmark.values.length)); for (final devToolsBenchmark in DevToolsBenchmark.values) { diff --git a/packages/devtools_app/benchmark/scripts/compare_benchmarks.dart b/packages/devtools_app/benchmark/scripts/compare_benchmarks.dart index 6b919c910ef..25c49634514 100644 --- a/packages/devtools_app/benchmark/scripts/compare_benchmarks.dart +++ b/packages/devtools_app/benchmark/scripts/compare_benchmarks.dart @@ -5,6 +5,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:devtools_app/src/shared/primitives/utils.dart'; import 'package:web_benchmarks/analysis.dart'; import 'utils.dart'; @@ -61,6 +62,6 @@ void compareBenchmarks( stdout.writeln('Baseline comparison finished.'); stdout ..writeln('==== Comparison with baseline $baselineSource ====') - ..writeln(const JsonEncoder.withIndent(' ').convert(delta.toJson())) + ..writeln(prettyPrintJson(delta.toJson())) ..writeln('==== End of baseline comparison ===='); } diff --git a/packages/devtools_app/integration_test/test_infra/run/_test_app_driver.dart b/packages/devtools_app/integration_test/test_infra/run/_test_app_driver.dart index cd3c843a291..4906faef256 100644 --- a/packages/devtools_app/integration_test/test_infra/run/_test_app_driver.dart +++ b/packages/devtools_app/integration_test/test_infra/run/_test_app_driver.dart @@ -389,11 +389,9 @@ final class FlutterDaemonConstants { static const paramsKey = 'params'; static const traceKey = 'trace'; static const wsUriKey = 'wsUri'; - static const pidKey = 'pid'; static const appStopKey = 'app.stop'; static const appStartedKey = 'app.started'; static const appDebugPortKey = 'app.debugPort'; - static const daemonConnectedKey = 'daemon.connected'; } enum TestAppDevice { diff --git a/packages/devtools_app/lib/src/screens/debugger/span_parser.dart b/packages/devtools_app/lib/src/screens/debugger/span_parser.dart index 74cbe0137ad..e1bf02884f1 100644 --- a/packages/devtools_app/lib/src/screens/debugger/span_parser.dart +++ b/packages/devtools_app/lib/src/screens/debugger/span_parser.dart @@ -3,11 +3,12 @@ // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. import 'dart:collection'; -import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:string_scanner/string_scanner.dart'; +import '../../shared/primitives/utils.dart'; + //TODO(jacobr): cleanup. /// A namespace for [SpanParser] utilities. extension SpanParser on Never { @@ -68,7 +69,7 @@ class Grammar { @override String toString() { - return const JsonEncoder.withIndent(' ').convert({ + return prettyPrintJson({ 'name': name, 'scopeName': scopeName, 'topLevelMatcher': topLevelMatcher.toJson(), diff --git a/packages/devtools_app/lib/src/screens/inspector/inspector_tree_controller.dart b/packages/devtools_app/lib/src/screens/inspector/inspector_tree_controller.dart index 130bec6a5a2..de13f6173f2 100644 --- a/packages/devtools_app/lib/src/screens/inspector/inspector_tree_controller.dart +++ b/packages/devtools_app/lib/src/screens/inspector/inspector_tree_controller.dart @@ -120,8 +120,7 @@ class InspectorTreeController extends DisposableController /// [InspectorTreeController]. final int? gaId; - InspectorTreeNode createNode() => - InspectorTreeNode(whenDirty: _handleDirtyNode); + InspectorTreeNode createNode() => InspectorTreeNode(); SearchTargetType _searchTarget = SearchTargetType.widget; int _rootSetCount = 0; @@ -284,15 +283,6 @@ class InspectorTreeController extends DisposableController } } - /// Resets the state if the root has been marked as dirty. - void _handleDirtyNode(InspectorTreeNode node) { - if (node == root) { - _cachedSelectedRow = null; - lastContentWidth = null; - _updateRows(); - } - } - void setSearchTarget(SearchTargetType searchTarget) { _searchTarget = searchTarget; refreshSearchMatches(); @@ -448,10 +438,6 @@ class InspectorTreeController extends DisposableController return inspectorRowHeight * index; } - void nodeChanged(InspectorTreeNode node) { - node.isDirty = true; - } - void removeNodeFromParent(InspectorTreeNode node) { node.parent?.removeChild(node); } @@ -767,7 +753,6 @@ class InspectorTreeController extends DisposableController setupChildren(diagnostic, treeNode, children, expandChildren: true); refreshTree( updateTreeAction: () { - nodeChanged(treeNode); if (treeNode == selection) { expandPath(treeNode); } 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 e92a3829ccf..3c570845d71 100644 --- a/packages/devtools_app/lib/src/screens/logging/logging_controller.dart +++ b/packages/devtools_app/lib/src/screens/logging/logging_controller.dart @@ -1016,8 +1016,6 @@ class LogData with SearchableDataMixin { String? _details; Future Function()? detailsComputer; - static const prettyPrinter = JsonEncoder.withIndent(' '); - String? get details => _details; bool get needsComputing => !detailsComputed.isCompleted; @@ -1040,10 +1038,9 @@ class LogData with SearchableDataMixin { } try { - return prettyPrinter - .convert(jsonDecode(details!)) - .replaceAll(r'\n', '\n') - .trim(); + return prettyPrintJson( + jsonDecode(details!) as Object?, + ).replaceAll(r'\n', '\n').trim(); } catch (_) { return details?.trim(); } diff --git a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart index aef066c8670..a6f371a3590 100644 --- a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart +++ b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart @@ -3,6 +3,7 @@ // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. // ignore_for_file: non_constant_identifier_names +// ignore_for_file: unused-code, platform specific imports. import 'dart:async'; diff --git a/packages/devtools_app/lib/src/shared/analytics/analytics_controller.dart b/packages/devtools_app/lib/src/shared/analytics/analytics_controller.dart index 52bb5710d0a..9d7c9684284 100644 --- a/packages/devtools_app/lib/src/shared/analytics/analytics_controller.dart +++ b/packages/devtools_app/lib/src/shared/analytics/analytics_controller.dart @@ -43,8 +43,6 @@ bool get isAnalyticsEnabled => /// Whether the analytics controller has been initialized. bool get isAnalyticsControllerInitialized => _analyticsController != null; -typedef AsyncAnalyticsCallback = FutureOr Function(); - class AnalyticsController { AnalyticsController({ required bool enabled, @@ -67,6 +65,7 @@ class AnalyticsController { ValueListenable get shouldPrompt => _shouldPrompt; final ValueNotifier _shouldPrompt; + @visibleForTesting bool get analyticsInitialized => _analyticsInitialized; bool _analyticsInitialized = false; diff --git a/packages/devtools_app/lib/src/shared/analytics/constants.dart b/packages/devtools_app/lib/src/shared/analytics/constants.dart index c56654fc5c2..1eb14d8df3d 100644 --- a/packages/devtools_app/lib/src/shared/analytics/constants.dart +++ b/packages/devtools_app/lib/src/shared/analytics/constants.dart @@ -99,13 +99,6 @@ const inspectorSettings = 'inspectorSettings'; const loggingSettings = 'loggingSettings'; const refreshPubRoots = 'refreshPubRoots'; -enum InspectorDetailsViewType { layoutExplorer, widgetDetailsTree } - -final defaultDetailsViewToLayoutExplorer = - InspectorDetailsViewType.layoutExplorer.name; -final defaultDetailsViewToWidgetDetails = - InspectorDetailsViewType.widgetDetailsTree.name; - enum HomeScreenEvents { connectToApp, connectToNewApp, viewVmFlags } // Logging UX actions: diff --git a/packages/devtools_app/lib/src/shared/analytics/constants/_cpu_profiler_constants.dart b/packages/devtools_app/lib/src/shared/analytics/constants/_cpu_profiler_constants.dart index 9920f33bb01..4a7c7ced742 100644 --- a/packages/devtools_app/lib/src/shared/analytics/constants/_cpu_profiler_constants.dart +++ b/packages/devtools_app/lib/src/shared/analytics/constants/_cpu_profiler_constants.dart @@ -7,7 +7,6 @@ part of '../constants.dart'; enum CpuProfilerEvents { profileGranularity, loadAllCpuSamples, - profileAppStartUp, cpuProfileFlameChartHelp, cpuProfileProcessingTime, openDataFile, diff --git a/packages/devtools_app/lib/src/shared/analytics/constants/_performance_constants.dart b/packages/devtools_app/lib/src/shared/analytics/constants/_performance_constants.dart index 1b548e82749..3b9bafb1a62 100644 --- a/packages/devtools_app/lib/src/shared/analytics/constants/_performance_constants.dart +++ b/packages/devtools_app/lib/src/shared/analytics/constants/_performance_constants.dart @@ -20,9 +20,6 @@ enum PerformanceEvents { disableOpacityLayers, disablePhysicalShapeLayers, countWidgetBuilds('trackRebuildWidgets'), - collectRasterStats, - clearRasterStats, - fullScreenLayerImage, clearRebuildStats, perfettoLoadTrace, perfettoScrollToTimeRange, @@ -55,6 +52,5 @@ enum PerformanceDocs { shaderCompilationDocs, shaderCompilationDocsTooltipLink, impellerDocsLink, - impellerDocsLinkFromRasterStats, platformChannelsDocs, } diff --git a/packages/devtools_app/lib/src/shared/analytics/metrics.dart b/packages/devtools_app/lib/src/shared/analytics/metrics.dart index 70a846566ce..595c0a1de61 100644 --- a/packages/devtools_app/lib/src/shared/analytics/metrics.dart +++ b/packages/devtools_app/lib/src/shared/analytics/metrics.dart @@ -74,7 +74,6 @@ class InspectorScreenMetrics extends ScreenAnalyticsMetrics { }); static const summaryTreeGaId = 0; - static const detailsTreeGaId = 1; /// The number of times the root has been set, since the /// [InspectorTreeController] with id [inspectorTreeControllerId], has been diff --git a/packages/devtools_app/lib/src/shared/charts/chart_trace.dart b/packages/devtools_app/lib/src/shared/charts/chart_trace.dart index d95f0b2e861..5e1ab4959ea 100644 --- a/packages/devtools_app/lib/src/shared/charts/chart_trace.dart +++ b/packages/devtools_app/lib/src/shared/charts/chart_trace.dart @@ -54,6 +54,7 @@ class PaintCharacteristics { /// If specified Y scale is computed and min value is fixed. /// Will assert if new data point is less than min specified. + // ignore: unused-code, TODO(https://github.com/flutter/devtools/issues/9910) seems like a bug. double? fixedMinY; /// If specified Y scale is computed and max value is fixed. @@ -88,11 +89,7 @@ class PaintCharacteristics { } class Trace { - Trace(this.controller, this._chartType, this.characteristics) { - final minY = characteristics.fixedMinY ?? 0.0; - final maxY = characteristics.fixedMaxY ?? 0.0; - yAxis = AxisScale(minY, maxY, 30); - } + Trace(this.controller, this._chartType, this.characteristics); final ChartController controller; @@ -113,6 +110,7 @@ class Trace { /// ------------------------------- late bool stacked; + // ignore: unused-code, false positive used in asserts. String? name; double dataYMax = 0; @@ -155,8 +153,6 @@ class Trace { ChartType get chartType => _chartType; - AxisScale? yAxis; - void clearData() { _data.clear(); controller.dirty = true; @@ -173,7 +169,6 @@ class Trace { ); } else if (datum.y > dataYMax) { dataYMax = datum.y.toDouble(); - yAxis = AxisScale(0, dataYMax, 30); } if (datum.y > controller.yMaxValue) { @@ -298,7 +293,6 @@ class AxisScale { fraction = 0; } return AxisScale._( - minPoint: minPoint, maxPoint: maxPoint, maxTicks: maxTicks, tickSpacing: tickSpacing, @@ -308,7 +302,6 @@ class AxisScale { } AxisScale._({ - required this.minPoint, required this.maxPoint, required this.maxTicks, required this.tickSpacing, @@ -316,8 +309,10 @@ class AxisScale { required this.labelTicks, }); - final double minPoint, maxPoint; + @visibleForTesting + final double maxPoint; + @visibleForTesting final double maxTicks; final double tickSpacing; diff --git a/packages/devtools_app/lib/src/shared/charts/flame_chart.dart b/packages/devtools_app/lib/src/shared/charts/flame_chart.dart index c33243e09fe..26aa5d80cc4 100644 --- a/packages/devtools_app/lib/src/shared/charts/flame_chart.dart +++ b/packages/devtools_app/lib/src/shared/charts/flame_chart.dart @@ -17,7 +17,6 @@ import '../primitives/extent_delegate_list.dart'; import '../primitives/flutter_widgets/linked_scroll_controller.dart'; import '../primitives/trees.dart'; import '../primitives/utils.dart'; -import '../ui/colors.dart'; import '../ui/common_widgets.dart'; import '../ui/search.dart'; import '../ui/utils.dart'; @@ -60,16 +59,8 @@ abstract class FlameChart extends StatefulWidget { }); static const minZoomLevel = 1.0; - static const zoomMultiplier = 0.01; static const minScrollOffset = 0.0; static const rowOffsetForBottomPadding = 1; - static const rowOffsetForSectionSpacer = 1; - - /// Maximum scroll delta allowed for scroll wheel based zooming. - /// - /// This isn't really needed but is a reasonable for safety in case we - /// aren't handling some mouse based scroll wheel behavior well, etc. - static const maxScrollWheelDelta = 20.0; final T data; @@ -103,7 +94,7 @@ abstract class FlameChartState< V extends FlameChartDataMixin > extends State - with AutoDisposeMixin, FlameChartColorMixin, TickerProviderStateMixin { + with AutoDisposeMixin, TickerProviderStateMixin { int get rowOffsetForTopPadding => 2; // The "top" positional value for each flame chart node will be 0.0 because @@ -112,8 +103,6 @@ abstract class FlameChartState< final rows = >[]; - final sections = []; - // ignore: dispose-fields, false positive. Disposed via autoDisposeFocusNode. final focusNode = FocusNode(debugLabel: 'flame-chart'); @@ -158,31 +147,6 @@ abstract class FlameChartState< double get widthWithZoom => contentWidthWithZoom + widget.startInset + widget.endInset; - TimeRange get visibleTimeRange { - final horizontalScrollOffset = horizontalControllerGroup.offset; - final startMicros = horizontalScrollOffset < widget.startInset - ? startTimeOffset - : startTimeOffset + - (horizontalScrollOffset - widget.startInset) / - currentZoom / - startingPxPerMicro; - - final endMicros = - startTimeOffset + - (horizontalScrollOffset - widget.startInset + widget.containerWidth) / - currentZoom / - startingPxPerMicro; - - return TimeRange(start: startMicros.round(), end: endMicros.round()); - } - - /// Starting pixels per microsecond in order to fit all the data in view at - /// start. - double get startingPxPerMicro => - widget.startingContentWidth / widget.time.duration.inMicroseconds; - - int get startTimeOffset => widget.time.start; - double get maxZoomLevel { // The max zoom level is hit when 1 microsecond is the width of each grid // interval (this may bottom out at 2 micros per interval due to rounding). @@ -371,13 +335,12 @@ abstract class FlameChartState< @mustCallSuper void initFlameChartElements() { rows.clear(); - sections.clear(); } void expandRows(int newRowLength) { final currentLength = rows.length; for (int i = currentLength; i < newRowLength; i++) { - rows.add(FlameChartRow(i)); + rows.add(FlameChartRow()); } } @@ -583,46 +546,6 @@ abstract class FlameChartState< await scrollToX(offset); } - Future zoomAndScrollToData({ - required int startMicros, - required int durationMicros, - required V data, - bool scrollVertically = true, - bool jumpZoom = false, - }) async { - await zoomToTimeRange( - startMicros: startMicros, - durationMicros: durationMicros, - jump: jumpZoom, - ); - // Call these in a post frame callback so that the scroll controllers have - // had time to update their scroll extents. Otherwise, we can hit a race - // where are trying to scroll to an offset that is beyond what the scroll - // controller thinks its max scroll extent is. - WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted) { - unawaited(scrollHorizontallyToData(data)); - if (scrollVertically) unawaited(scrollVerticallyToData(data)); - } - }); - } - - Future zoomToTimeRange({ - required int startMicros, - required int durationMicros, - double? targetWidth, - bool jump = false, - }) async { - targetWidth ??= widget.containerWidth * 0.8; - final startingWidth = durationMicros * startingPxPerMicro; - final zoom = targetWidth / startingWidth; - final mouseXForZoom = - (startMicros - startTimeOffset + durationMicros / 2) * - startingPxPerMicro + - widget.startInset; - await zoomTo(zoom, forceMouseX: mouseXForZoom, jump: jump); - } - bool isDataVerticallyInView(V data); bool isDataHorizontallyInView(V data); @@ -699,9 +622,6 @@ class ScrollingFlameChartRowState> chartStartInset: widget.startInset, chartWidth: widget.width, ), - zoom: widget.zoom, - chartStartInset: widget.startInset, - chartWidth: widget.width, ); _initNodeDataList(); @@ -751,9 +671,6 @@ class ScrollingFlameChartRowState> chartStartInset: widget.startInset, chartWidth: widget.width, ), - zoom: widget.zoom, - chartStartInset: widget.startInset, - chartWidth: widget.width, ); } _resetHovered(); @@ -979,25 +896,9 @@ extension FlameChartUtils on Never { } } -class FlameChartSection { - FlameChartSection(this.index, {required this.startRow, required this.endRow}); - - final int index; - - /// Start row (inclusive) for this section. - final int startRow; - - /// End row (exclusive) for this section. - final int endRow; -} - class FlameChartRow> { - FlameChartRow(this.index); - final nodes = >[]; - final int index; - /// Adds a node to [nodes] and assigns `this` to the node's `row` property. /// /// If [index] is specified and in range of the list, [node] will be added at @@ -1008,7 +909,6 @@ class FlameChartRow> { } else { nodes.add(node); } - node.row = this; } } @@ -1046,8 +946,6 @@ class FlameChartNode> { final void Function(T) onSelected; final bool selectable; - late FlameChartRow row; - int sectionIndex; Widget buildWidget({ @@ -1150,54 +1048,17 @@ class FlameChartNode> { } } -mixin FlameChartColorMixin { - ColorPair nextUiColor(int row) { - return uiColorPalette[row % uiColorPalette.length]; - } - - ColorPair nextRasterColor(int row) { - return rasterColorPalette[row % rasterColorPalette.length]; - } - - ColorPair nextAsyncColor(int row) { - return asyncColorPalette[row % asyncColorPalette.length]; - } - - ColorPair nextUnknownColor(int row) { - return unknownColorPalette[row % unknownColorPalette.length]; - } -} - /// [ExtentDelegate] implementation for the case where size and position is /// known for each list item. class _ScrollingFlameChartRowExtentDelegate extends ExtentDelegate { - _ScrollingFlameChartRowExtentDelegate({ - required this.nodeIntervals, - required this.zoom, - required this.chartStartInset, - required this.chartWidth, - }) { + _ScrollingFlameChartRowExtentDelegate({required this.nodeIntervals}) { recompute(); } List nodeIntervals = []; - double zoom; - - double chartStartInset; - - double chartWidth; - - void recomputeWith({ - required List nodeIntervals, - required double zoom, - required double chartStartInset, - required double chartWidth, - }) { + void recomputeWith({required List nodeIntervals}) { this.nodeIntervals = nodeIntervals; - this.zoom = zoom; - this.chartStartInset = chartStartInset; - this.chartWidth = chartWidth; recompute(); } diff --git a/packages/devtools_app/lib/src/shared/charts/treemap.dart b/packages/devtools_app/lib/src/shared/charts/treemap.dart index 9b0db9a44ac..f6a77d5c415 100644 --- a/packages/devtools_app/lib/src/shared/charts/treemap.dart +++ b/packages/devtools_app/lib/src/shared/charts/treemap.dart @@ -6,7 +6,6 @@ import 'package:devtools_app_shared/ui.dart'; import 'package:devtools_app_shared/utils.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:logging/logging.dart'; import '../primitives/byte_utils.dart'; import '../primitives/trees.dart'; @@ -15,8 +14,6 @@ import '../ui/common_widgets.dart'; enum PivotType { pivotByMiddle, pivotBySize } -final _log = Logger('charts/treemap'); - class Treemap extends StatefulWidget { // TODO(peterdjlee): Consider auto-expanding rootNode named 'src'. const Treemap.fromRoot({ @@ -683,7 +680,10 @@ class TreemapNode extends TreeNode { }); final String name; + + // ignore: unused-code, TODO(https://github.com/flutter/devtools/issues/9910) seems like a bug. final Map childrenMap; + int byteSize; final bool showDiff; @@ -794,17 +794,6 @@ class TreemapNode extends TreeNode { return []; } - void printTree() { - printTreeHelper(this, ''); - } - - void printTreeHelper(TreemapNode root, String tabs) { - _log.info('$tabs$root'); - for (final child in root.children) { - printTreeHelper(child, '$tabs\t'); - } - } - @override String toString() { return '{name: $name, size: $byteSize}'; diff --git a/packages/devtools_app/lib/src/shared/config_specific/drag_and_drop/drag_and_drop.dart b/packages/devtools_app/lib/src/shared/config_specific/drag_and_drop/drag_and_drop.dart index 233de4798b0..9ba1f8f0aeb 100644 --- a/packages/devtools_app/lib/src/shared/config_specific/drag_and_drop/drag_and_drop.dart +++ b/packages/devtools_app/lib/src/shared/config_specific/drag_and_drop/drag_and_drop.dart @@ -24,8 +24,6 @@ abstract class DragAndDropManager { int get viewId => _viewId; final int _viewId; - final _dragAndDropStates = {}; - DragAndDropState? activeState; /// The method is abstract, because we want to force descendants to define it. @@ -37,18 +35,9 @@ abstract class DragAndDropManager { @mustCallSuper void dispose() { - _dragAndDropStates.clear(); activeState = null; } - void registerDragAndDrop(DragAndDropState state) { - _dragAndDropStates.add(state); - } - - void unregisterDragAndDrop(DragAndDropState state) { - _dragAndDropStates.remove(state); - } - void dragOver(double x, double y) { hitTestAndUpdateActiveId(x, y); activeState?.dragOver(); @@ -126,12 +115,10 @@ class DragAndDropState extends State { // Already registered to the right drag and drop manager, so do nothing. if (oldViewId == viewId) return; - _dragAndDropManager?.unregisterDragAndDrop(this); _dragAndDropManager = null; } _dragAndDropManager = DragAndDropManager.getInstance(viewId); - _dragAndDropManager!.registerDragAndDrop(this); } @override @@ -141,7 +128,6 @@ class DragAndDropState extends State { @override void dispose() { - _dragAndDropManager?.unregisterDragAndDrop(this); _dragAndDropManager = null; _dragging.dispose(); super.dispose(); diff --git a/packages/devtools_app/lib/src/shared/config_specific/framework_initialize/_framework_initialize_desktop.dart b/packages/devtools_app/lib/src/shared/config_specific/framework_initialize/_framework_initialize_desktop.dart index b1f9630f12a..1c8710aa9d8 100644 --- a/packages/devtools_app/lib/src/shared/config_specific/framework_initialize/_framework_initialize_desktop.dart +++ b/packages/devtools_app/lib/src/shared/config_specific/framework_initialize/_framework_initialize_desktop.dart @@ -10,6 +10,7 @@ import 'package:logging/logging.dart'; import 'package:path/path.dart' as path; import '../../primitives/storage.dart'; +import '../../primitives/utils.dart'; final _log = Logger('_framework_initialize_desktop'); @@ -32,12 +33,11 @@ class FlutterDesktopStorage implements Storage { Future setValue(String key, String value) async { _values[key] = value; - const encoder = JsonEncoder.withIndent(' '); if (!_fileAndDirVerified) { File(_preferencesFile.path).createSync(recursive: true); _fileAndDirVerified = true; } - _preferencesFile.writeAsStringSync('${encoder.convert(_values)}\n'); + _preferencesFile.writeAsStringSync('${prettyPrintJson(_values)}\n'); } Map _readValues() { diff --git a/packages/devtools_app/lib/src/shared/config_specific/import_export/_file_desktop.dart b/packages/devtools_app/lib/src/shared/config_specific/import_export/_file_desktop.dart index 11179bde55d..eaa737091e2 100644 --- a/packages/devtools_app/lib/src/shared/config_specific/import_export/_file_desktop.dart +++ b/packages/devtools_app/lib/src/shared/config_specific/import_export/_file_desktop.dart @@ -6,18 +6,11 @@ import 'dart:typed_data'; import 'package:file/file.dart'; import 'package:file/local.dart'; -import 'package:logging/logging.dart'; -import 'package:path/path.dart' as path; - -final _log = Logger('_file_desktop'); /// Abstracted local file system access for Flutter Desktop. class FileSystemDesktop { final _fs = const LocalFileSystem(); - String exportDirectoryName({bool isMemory = false}) => - _exportDirectory(isMemory: isMemory).path; - /// Flutter Desktop MacOS systemTempDirectory is in Downloads /// for memory files location is $TMPDIR. /// Flutter Desktop Linux systemTempDirectory is \tmp @@ -54,70 +47,4 @@ class FileSystemDesktop { throw StateError('Unsupported content type: $T'); } } - - /// Returns content of filename or null if file is unknown or content empty. - String readStringFromFile(String filename, {bool isMemory = false}) { - final previousCurrentDirectory = _fs.currentDirectory; - - // TODO(terry): Use path_provider when available? - _fs.currentDirectory = _exportDirectory(isMemory: isMemory); - - final logFile = _fs.currentDirectory.childFile(filename); - - final jsonPayload = logFile.readAsStringSync(); - - _fs.currentDirectory = previousCurrentDirectory; - - return jsonPayload; - } - - /// List of files (basename only). - List list({required String prefix, bool isMemory = false}) { - final logs = []; - - try { - // TODO(terry): Use path_provider when available? - final directory = _exportDirectory(isMemory: isMemory); - - if (!directory.existsSync()) { - return logs; - } - - final allFiles = directory.listSync(followLinks: false); - for (final entry in allFiles) { - final basename = path.basename(entry.path); - if (_fs.isFileSync(entry.path) && basename.startsWith(prefix)) { - logs.add(basename); - } - } - - // Sort by newest file top-most (DateTime is in the filename). - logs.sort((a, b) => b.compareTo(a)); - } on FileSystemException catch (e, st) { - // TODO(jacobr): prompt the user to grant permission to access the - // directory if Flutter ever provides that option or consider using an - // alternate directory. This error should generally only occur on MacOS - // desktop Catalina and later where access to the Downloads folder - // is not granted by default. - _log.info(e, e, st); - } - - return logs; - } - - /// Delete exported files created for testing only. - bool deleteFile(String path, {bool isMemory = false}) { - final previousCurrentDirectory = _fs.currentDirectory; - - // TODO(terry): Use path_provider when available? - _fs.currentDirectory = _exportDirectory(isMemory: isMemory); - - if (!_fs.isFileSync(path)) return false; - - _fs.file(path).deleteSync(); - - _fs.currentDirectory = previousCurrentDirectory; - - return true; - } } diff --git a/packages/devtools_app/lib/src/shared/config_specific/import_export/import_export.dart b/packages/devtools_app/lib/src/shared/config_specific/import_export/import_export.dart index 442151fb282..eed968af961 100644 --- a/packages/devtools_app/lib/src/shared/config_specific/import_export/import_export.dart +++ b/packages/devtools_app/lib/src/shared/config_specific/import_export/import_export.dart @@ -113,7 +113,6 @@ extension type _DevToolsOfflineData(Map json) { enum ExportFileType { json, csv, - yaml, data, har; diff --git a/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_stub.dart b/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_stub.dart index a84be62e287..6f3dfb0a40d 100644 --- a/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_stub.dart +++ b/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_stub.dart @@ -7,5 +7,6 @@ import 'post_message.dart'; Stream get onPostMessage => throw UnsupportedError('unsupported platform'); +// ignore: unused-code, currently unused but an important helper to keep. void postMessage(Object? _, String _) => throw UnsupportedError('unsupported platform'); diff --git a/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_web.dart b/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_web.dart index b59605a3f95..423c7da52f3 100644 --- a/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_web.dart +++ b/packages/devtools_app/lib/src/shared/config_specific/post_message/_post_message_web.dart @@ -2,6 +2,8 @@ // 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. +// ignore_for_file: unused-code, platform specific imports. + import 'dart:js_interop'; import 'package:web/web.dart'; @@ -10,8 +12,7 @@ import 'post_message.dart'; Stream get onPostMessage { return window.onMessage.map( - (message) => - PostMessageEvent(origin: message.origin, data: message.data.dartify()), + (message) => PostMessageEvent(data: message.data.dartify()), ); } diff --git a/packages/devtools_app/lib/src/shared/config_specific/post_message/post_message.dart b/packages/devtools_app/lib/src/shared/config_specific/post_message/post_message.dart index bf9ba98cc7c..fc3071dd9d1 100644 --- a/packages/devtools_app/lib/src/shared/config_specific/post_message/post_message.dart +++ b/packages/devtools_app/lib/src/shared/config_specific/post_message/post_message.dart @@ -6,8 +6,7 @@ export '_post_message_stub.dart' if (dart.library.js_interop) '_post_message_web.dart'; class PostMessageEvent { - PostMessageEvent({required this.origin, required this.data}); + PostMessageEvent({required this.data}); - final String origin; final Object? data; } diff --git a/packages/devtools_app/lib/src/shared/console/eval/inspector_tree.dart b/packages/devtools_app/lib/src/shared/console/eval/inspector_tree.dart index c505152acad..2d699439e92 100644 --- a/packages/devtools_app/lib/src/shared/console/eval/inspector_tree.dart +++ b/packages/devtools_app/lib/src/shared/console/eval/inspector_tree.dart @@ -33,37 +33,14 @@ const inspectorRowHeight = 20.0; /// specific as that is the only case we care about. // TODO(kenz): extend TreeNode class to share tree logic. class InspectorTreeNode { - InspectorTreeNode({ - InspectorTreeNode? parent, - bool expandChildren = true, - this.whenDirty, - }) : _children = [], - _parent = parent, - _isExpanded = expandChildren; - - /// Callback that is called when the node is marked as dirty. - void Function(InspectorTreeNode node)? whenDirty; + InspectorTreeNode({this.parent, bool expandChildren = true}) + : _children = [], + _isExpanded = expandChildren; bool get showLinesToChildren { return _children.length > 1 && !_children.last.isProperty; } - bool get isDirty => _isDirty; - bool _isDirty = true; - - set isDirty(bool dirty) { - if (dirty) { - _isDirty = true; - _shouldShow = null; - if (parent != null) { - parent!.isDirty = true; - } - whenDirty?.call(this); - } else { - _isDirty = false; - } - } - /// Returns whether the node is currently visible in the tree. void updateShouldShow(bool value) { if (value != _shouldShow) { @@ -108,7 +85,6 @@ class InspectorTreeNode { set isExpanded(bool value) { if (value != _isExpanded) { _isExpanded = value; - isDirty = true; if (_shouldShow ?? false) { for (final child in children) { child.updateShouldShow(value); @@ -117,13 +93,7 @@ class InspectorTreeNode { } } - InspectorTreeNode? get parent => _parent; - InspectorTreeNode? _parent; - - set parent(InspectorTreeNode? value) { - _parent = value; - _parent?.isDirty = true; - } + InspectorTreeNode? parent; RemoteDiagnosticsNode? get diagnostic => _diagnostic; @@ -131,7 +101,6 @@ class InspectorTreeNode { final value = v!; _diagnostic = value; _isExpanded = value.childrenReady; - isDirty = true; } bool get hasPlaceholderChildren { @@ -142,18 +111,15 @@ class InspectorTreeNode { child.parent = null; final removed = _children.remove(child); assert(removed); - isDirty = true; } void appendChild(InspectorTreeNode child) { _children.add(child); child.parent = this; - isDirty = true; } void clearChildren() { _children.clear(); - isDirty = true; } } diff --git a/packages/devtools_app/lib/src/shared/console/primitives/eval_history.dart b/packages/devtools_app/lib/src/shared/console/primitives/eval_history.dart index a94ec5f1a21..39c7763af88 100644 --- a/packages/devtools_app/lib/src/shared/console/primitives/eval_history.dart +++ b/packages/devtools_app/lib/src/shared/console/primitives/eval_history.dart @@ -2,11 +2,14 @@ // 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:meta/meta.dart'; + /// Store and manipulate the expression evaluation history. class EvalHistory { var _historyPosition = -1; /// Get the expression evaluation history. + @visibleForTesting List get evalHistory => _evalHistory.toList(); final _evalHistory = []; diff --git a/packages/devtools_app/lib/src/shared/console/widgets/description.dart b/packages/devtools_app/lib/src/shared/console/widgets/description.dart index 1d914afccd6..2344aed2cce 100644 --- a/packages/devtools_app/lib/src/shared/console/widgets/description.dart +++ b/packages/devtools_app/lib/src/shared/console/widgets/description.dart @@ -111,7 +111,7 @@ class DiagnosticsNodeDescription extends StatelessWidget { TextSpan(text: name, style: textStyle), ); } else { - final approximateIconWidth = IconKind.info.icon.width + iconPadding; + final approximateIconWidth = infoIcon.width + iconPadding; // When there is no name, an icon will be shown with the text spans. spanWidth += approximateIconWidth; diff --git a/packages/devtools_app/lib/src/shared/console/widgets/display_provider.dart b/packages/devtools_app/lib/src/shared/console/widgets/display_provider.dart index 4e389efb5e3..91fd7ac7fee 100644 --- a/packages/devtools_app/lib/src/shared/console/widgets/display_provider.dart +++ b/packages/devtools_app/lib/src/shared/console/widgets/display_provider.dart @@ -255,6 +255,7 @@ class DapDisplayProvider extends StatelessWidget { }); final DapObjectNode node; + // ignore: unused-code, TODO(https://github.com/flutter/devtools/issues/6056) implement onTap. final VoidCallback onTap; @override diff --git a/packages/devtools_app/lib/src/shared/console/widgets/evaluate.dart b/packages/devtools_app/lib/src/shared/console/widgets/evaluate.dart index e7c07d9704a..ea2437306cd 100644 --- a/packages/devtools_app/lib/src/shared/console/widgets/evaluate.dart +++ b/packages/devtools_app/lib/src/shared/console/widgets/evaluate.dart @@ -46,8 +46,6 @@ class ExpressionEvalFieldState extends State final _autoCompleteController = AutoCompleteController(evalTextFieldKey); - int historyPosition = -1; - String _activeWord = ''; List _matches = []; @@ -318,7 +316,6 @@ class ExpressionEvalFieldState extends State serviceConnection.consoleService.appendStdio('> $expressionText\n'); setState(() { - historyPosition = -1; serviceConnection.appState.evalHistory.pushEvalHistory(expressionText); }); diff --git a/packages/devtools_app/lib/src/shared/development_helpers.dart b/packages/devtools_app/lib/src/shared/development_helpers.dart index 42c10f19f9d..072e8049905 100644 --- a/packages/devtools_app/lib/src/shared/development_helpers.dart +++ b/packages/devtools_app/lib/src/shared/development_helpers.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. +// ignore_for_file: unused-code, intentional helpers for development only. import 'dart:async'; import 'package:devtools_shared/devtools_extensions.dart'; diff --git a/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart b/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart index f6cc1a7f01f..5b0ac2a9129 100644 --- a/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart +++ b/packages/devtools_app/lib/src/shared/diagnostics/dart_object_node.dart @@ -8,7 +8,6 @@ library; import 'dart:async'; import 'package:devtools_app_shared/utils.dart'; -import 'package:flutter/foundation.dart'; import 'package:vm_service/vm_service.dart'; import '../globals.dart'; @@ -33,9 +32,7 @@ class DartObjectNode extends TreeNode { this.artificialValue = false, this.isRerootable = false, }) : _offset = offset, - _childCount = childCount { - indentChildren = ref?.diagnostic?.style != DiagnosticsTreeStyle.flat; - } + _childCount = childCount; /// Creates a variable from a value that must be an VM service type or a /// primitive type. diff --git a/packages/devtools_app/lib/src/shared/diagnostics/diagnostics_node.dart b/packages/devtools_app/lib/src/shared/diagnostics/diagnostics_node.dart index 9f07dbbdb40..128f2cba2be 100644 --- a/packages/devtools_app/lib/src/shared/diagnostics/diagnostics_node.dart +++ b/packages/devtools_app/lib/src/shared/diagnostics/diagnostics_node.dart @@ -83,8 +83,6 @@ class RemoteDiagnosticsNode extends DiagnosticableTree { /// This node's parent (if it's been set). RemoteDiagnosticsNode? parent; - Future? propertyDocFuture; - List? cachedProperties; /// Service used to retrieve more detailed information about the value of @@ -101,8 +99,6 @@ class RemoteDiagnosticsNode extends DiagnosticableTree { // TODO(albertusangga): Refactor to cleaner/more robust solution bool get isFlex => ['Row', 'Column', 'Flex'].contains(widgetRuntimeType); - bool get isBox => json['isBox'] == true; - int? get flexFactor => json['flexFactor'] as int?; FlexFit get flexFit => deserializeFlexFit(json['flexFit'] as String?); diff --git a/packages/devtools_app/lib/src/shared/editor/api_classes.dart b/packages/devtools_app/lib/src/shared/editor/api_classes.dart index b30b3a32c20..3231269b698 100644 --- a/packages/devtools_app/lib/src/shared/editor/api_classes.dart +++ b/packages/devtools_app/lib/src/shared/editor/api_classes.dart @@ -139,7 +139,6 @@ abstract class Field { static const isEditable = 'isEditable'; static const isNullable = 'isNullable'; static const isRequired = 'isRequired'; - static const kind = 'kind'; static const line = 'line'; static const name = 'name'; static const options = 'options'; diff --git a/packages/devtools_app/lib/src/shared/editor/editor_client.dart b/packages/devtools_app/lib/src/shared/editor/editor_client.dart index 951790de13d..9dab74c5fad 100644 --- a/packages/devtools_app/lib/src/shared/editor/editor_client.dart +++ b/packages/devtools_app/lib/src/shared/editor/editor_client.dart @@ -2,6 +2,8 @@ // 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. +// ignore_for_file: unused-code, this file represents the full editor API. + import 'dart:async'; import 'package:devtools_app_shared/service.dart'; diff --git a/packages/devtools_app/lib/src/shared/feature_flags.dart b/packages/devtools_app/lib/src/shared/feature_flags.dart index 937c75108a6..ca86bb35c1b 100644 --- a/packages/devtools_app/lib/src/shared/feature_flags.dart +++ b/packages/devtools_app/lib/src/shared/feature_flags.dart @@ -93,6 +93,7 @@ extension FeatureFlags on Never { static final _flutterChannelFlags = {}; /// A helper to print the status of all the feature flags. + // ignore: unused-code, debug only method to be used as needed. static void debugPrintFeatureFlags({ConnectedApp? connectedApp}) { for (final entry in _booleanFlags) { _log.config(entry.toString()); @@ -141,6 +142,7 @@ class BooleanFeatureFlag { /// 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. +// ignore: unused-code, we want to support this type of feature flag. class FlutterChannelFeatureFlag { const FlutterChannelFeatureFlag({ required this.name, diff --git a/packages/devtools_app/lib/src/shared/framework/app_error_handling.dart b/packages/devtools_app/lib/src/shared/framework/app_error_handling.dart index 68ad3953e21..dbfbf6a5ba1 100644 --- a/packages/devtools_app/lib/src/shared/framework/app_error_handling.dart +++ b/packages/devtools_app/lib/src/shared/framework/app_error_handling.dart @@ -109,7 +109,10 @@ Future _reportError( } } +// ignore: unused-code, TODO(https://github.com/flutter/devtools/issues/9910) seems like a bug. SingleMapping? _cachedJsSourceMapping; + +// ignore: unused-code, TODO(https://github.com/flutter/devtools/issues/9910) seems like a bug. SingleMapping? _cachedWasmSourceMapping; Future _fetchSourceMapping() async { diff --git a/packages/devtools_app/lib/src/shared/framework/routing.dart b/packages/devtools_app/lib/src/shared/framework/routing.dart index d72d7e1c196..5de3eabe6d6 100644 --- a/packages/devtools_app/lib/src/shared/framework/routing.dart +++ b/packages/devtools_app/lib/src/shared/framework/routing.dart @@ -34,6 +34,7 @@ class DevToolsRouteInformationParser DevToolsRouteInformationParser() : _testQueryParams = null; @visibleForTesting + // ignore: unused-code, used in packages/devtools_test DevToolsRouteInformationParser.test(this._testQueryParams); /// Query parameters that can be set on DevTools routes for testing purposes. @@ -103,6 +104,7 @@ class DevToolsRouterDelegate extends RouterDelegate _isTestMode = false; @visibleForTesting + // ignore: unused-code, used in packages/devtools_test DevToolsRouterDelegate.test(this._getPage, [GlobalKey? key]) : navigatorKey = key ?? GlobalKey(), _isTestMode = true; @@ -273,6 +275,7 @@ class DevToolsRouterDelegate extends RouterDelegate await updateArgsIfChanged({'uri': null}); } + @visibleForTesting Future replaceState(DevToolsNavigationState state) async { final currentConfig = currentConfiguration!; await _replaceStack( @@ -381,6 +384,7 @@ class DevToolsNavigationState { @override String toString() => _state.toString(); + // ignore: unused-code, implicit method used in JSON serialization. Map toJson() => _state; } diff --git a/packages/devtools_app/lib/src/shared/framework/screen.dart b/packages/devtools_app/lib/src/shared/framework/screen.dart index 2bfe341a5fd..6e090ff7bc0 100644 --- a/packages/devtools_app/lib/src/shared/framework/screen.dart +++ b/packages/devtools_app/lib/src/shared/framework/screen.dart @@ -73,6 +73,8 @@ enum ScreenMetaData { debugger( 'debugger', title: 'Debugger', + // TODO(kenz): see if we can use a meterial icon or an asset icon so that + // we can remove the Octicons font family. icon: Octicons.bug, requiresDebugBuild: true, tutorialVideoTimestamp: '?t=513', diff --git a/packages/devtools_app/lib/src/shared/globals.dart b/packages/devtools_app/lib/src/shared/globals.dart index d4f70552d42..23f23257e7f 100644 --- a/packages/devtools_app/lib/src/shared/globals.dart +++ b/packages/devtools_app/lib/src/shared/globals.dart @@ -5,7 +5,6 @@ import 'package:devtools_app_shared/service.dart'; import 'package:devtools_app_shared/utils.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; import '../extensions/extension_service.dart'; import '../screens/debugger/breakpoint_manager.dart'; @@ -26,6 +25,8 @@ import 'primitives/storage.dart'; /// Whether this DevTools build is external. bool get isExternalBuild => _isExternalBuild; bool _isExternalBuild = true; + +// ignore: unused-code, used in g3. void setInternalBuild() => _isExternalBuild = false; ScreenControllers get screenControllers => @@ -70,9 +71,6 @@ EvalService get evalService => globals[EvalService] as EvalService; ExtensionService get extensionService => globals[ExtensionService] as ExtensionService; -GlobalKey get navigatorKey => - globals[GlobalKey] as GlobalKey; - /// Whether DevTools is being run in integration test mode. bool get integrationTestMode => _integrationTestMode; bool _integrationTestMode = false; @@ -83,6 +81,7 @@ void setIntegrationTestMode() { /// Whether DevTools is being run in a test environment. bool get testMode => _testMode; bool _testMode = false; +@visibleForTesting void setTestMode() { _testMode = true; } @@ -90,6 +89,7 @@ void setTestMode() { /// Whether DevTools is being run as a stager app. bool get stagerMode => _stagerMode; bool _stagerMode = false; +@visibleForTesting void setStagerMode() { if (!kReleaseMode) { _stagerMode = true; diff --git a/packages/devtools_app/lib/src/shared/http/_http_cookies.dart b/packages/devtools_app/lib/src/shared/http/_http_cookies.dart index ca49ed825c7..d0274d393b2 100644 --- a/packages/devtools_app/lib/src/shared/http/_http_cookies.dart +++ b/packages/devtools_app/lib/src/shared/http/_http_cookies.dart @@ -21,7 +21,6 @@ class Cookie { String? _name; String? _value; DateTime? expires; - int? maxAge; String? domain; String? path; bool httpOnly = false; @@ -30,16 +29,6 @@ class Cookie { String? get name => _name; String? get value => _value; - set name(String? newName) { - _validateName(newName); - _name = newName; - } - - set value(String? newValue) { - _validateValue(newValue); - _value = newValue; - } - Cookie.fromSetCookieValue(String value) { // Parse the 'set-cookie' header value. _parseSetCookieValue(value); @@ -105,8 +94,6 @@ class Cookie { } if (name == "expires") { expires = HttpDate._parseCookieDate(value); - } else if (name == "max-age") { - maxAge = int.parse(value); } else if (name == "domain") { domain = value; } else if (name == "path") { diff --git a/packages/devtools_app/lib/src/shared/http/constants.dart b/packages/devtools_app/lib/src/shared/http/constants.dart index abc7c09b687..7695a56be60 100644 --- a/packages/devtools_app/lib/src/shared/http/constants.dart +++ b/packages/devtools_app/lib/src/shared/http/constants.dart @@ -4,47 +4,20 @@ enum HttpRequestDataKeys { connectionInfo, - remoteAddress, - localPort, contentLength, - startedDateTime, - time, request, method, - url, - httpVersion, cookies, headers, - queryString, - postData, - mimeType, text, - headersSize, - bodySize, followRedirects, maxRedirects, persistentConnection, proxyDetails, - proxy, - type, error, response, - status, statusCode, - statusText, redirects, - redirectURL, - cache, - timings, - blocked, - dns, - connect, - send, - wait, - receive, - ssl, - connection, - comment, isolateId, uri, id, @@ -55,10 +28,6 @@ enum HttpRequestDataKeys { compressionState, isRedirect, reasonPhrase, - queryParameters, - content, - size, - connectionId, requestBody, responseBody, endTime, @@ -67,13 +36,3 @@ enum HttpRequestDataKeys { username, isDirect, } - -enum HttpRequestDataValues { json } - -class HttpRequestDataDefaults { - static const none = 'None'; - static const error = 'Error'; - static const httpVersion = 'HTTP/2.0'; - static const json = 'json'; - static const httpProfileRequest = '@HttpProfileRequest'; -} diff --git a/packages/devtools_app/lib/src/shared/http/http_request_data.dart b/packages/devtools_app/lib/src/shared/http/http_request_data.dart index 81ec0d35528..619db21ec71 100644 --- a/packages/devtools_app/lib/src/shared/http/http_request_data.dart +++ b/packages/devtools_app/lib/src/shared/http/http_request_data.dart @@ -315,6 +315,7 @@ class DartIOHttpRequestData extends NetworkRequest { Map? get responseHeaders => _request.response?.headers; /// The query parameters for the request. + @visibleForTesting Map? get queryParameters => _request.uri.queryParameters; @override diff --git a/packages/devtools_app/lib/src/shared/managers/banner_messages.dart b/packages/devtools_app/lib/src/shared/managers/banner_messages.dart index 536dc11c2ef..d9c32156880 100644 --- a/packages/devtools_app/lib/src/shared/managers/banner_messages.dart +++ b/packages/devtools_app/lib/src/shared/managers/banner_messages.dart @@ -319,6 +319,7 @@ class BannerWarning extends BannerMessage { }) : super(messageType: BannerMessageType.warning); } +// ignore: unused-code, this is a type of message we want to support. class BannerInfo extends BannerMessage { const BannerInfo({ required super.key, @@ -521,34 +522,6 @@ The $codeType DevTools debugger is in maintenance mode. For the best debugging e ); } -class LegacyInspectorWarningMessage extends BannerWarning { - LegacyInspectorWarningMessage({required super.screenId}) - : super( - key: buildKey(screenId), - buildTextSpans: (context) => [ - const TextSpan( - text: - 'The legacy inspector will be removed in a future release. ' - 'Please enable the new inspector in the inspector settings. ' - 'If there is an issue preventing you from using the new ' - 'inspector, please file a ', - ), - GaLinkTextSpan( - link: const GaLink( - display: 'bug', - url: 'https://github.com/flutter/devtools/issues/new', - ), - context: context, - style: Theme.of(context).linkTextStyle, - ), - const TextSpan(text: '.'), - ], - ); - - static Key buildKey(String screenId) => - Key('LegacyInspectorWarningMessage - $screenId'); -} - void maybePushDebugModePerformanceMessage(String screenId) { if (offlineDataController.showingOfflineData.value) return; if (serviceConnection.serviceManager.connectedApp?.isDebugFlutterAppNow ?? @@ -577,10 +550,6 @@ void pushDebuggerIdeRecommendationMessage(String screenId) { ); } -void pushLegacyInspectorWarning(String screenId) { - bannerMessages.addMessage(LegacyInspectorWarningMessage(screenId: screenId)); -} - extension BannerMessageThemeExtension on ThemeData { TextStyle get warningMessageLinkStyle => regularTextStyle.copyWith( decoration: TextDecoration.underline, diff --git a/packages/devtools_app/lib/src/shared/managers/script_manager.dart b/packages/devtools_app/lib/src/shared/managers/script_manager.dart index 02179f73d30..29d7a01d72c 100644 --- a/packages/devtools_app/lib/src/shared/managers/script_manager.dart +++ b/packages/devtools_app/lib/src/shared/managers/script_manager.dart @@ -76,17 +76,12 @@ class ScriptManager extends DisposableController Future getScript(ScriptRef scriptRef) { return _scriptCache.getScript(_service, _currentIsolate, scriptRef); } - - Script? getScriptByUri(String uri) { - return _scriptCache.getScriptByUri(uri); - } } class _ScriptCache { _ScriptCache(); final _scripts = {}; - final _uriToScript = {}; final _inProgress = >{}; /// Return a cached [Script] for the given [ScriptRef], returning null @@ -95,10 +90,6 @@ class _ScriptCache { return _scripts[scriptRef.id]; } - Script? getScriptByUri(String uri) { - return _uriToScript[uri]; - } - /// Retrieve the [Script] for the given [ScriptRef]. /// /// This caches the script lookup for future invocations. @@ -130,7 +121,6 @@ class _ScriptCache { unawaited( scriptFuture.then((script) { scripts[scriptId] = script; - _uriToScript[script.uri!] = script; }), ); diff --git a/packages/devtools_app/lib/src/shared/memory/class_name.dart b/packages/devtools_app/lib/src/shared/memory/class_name.dart index c1e9f7db2ce..c966b4c8a7c 100644 --- a/packages/devtools_app/lib/src/shared/memory/class_name.dart +++ b/packages/devtools_app/lib/src/shared/memory/class_name.dart @@ -143,6 +143,7 @@ class HeapClassName with Serializable { /// Whether a class can hold a reference to an object /// without preventing garbage collection. + // ignore: unused-code, TODO(https://github.com/flutter/devtools/issues/9907) false positive. late final isWeak = _isWeak(className, library); /// See [isWeak]. diff --git a/packages/devtools_app/lib/src/shared/memory/heap_data.dart b/packages/devtools_app/lib/src/shared/memory/heap_data.dart index 54fc1fb5316..5c4bf6f9117 100644 --- a/packages/devtools_app/lib/src/shared/memory/heap_data.dart +++ b/packages/devtools_app/lib/src/shared/memory/heap_data.dart @@ -25,7 +25,6 @@ class HeapData { Future get calculate => _calculated.future; final _calculated = Completer(); - bool get isCalculated => _calculated.isCompleted; ClassDataList? classes; diff --git a/packages/devtools_app/lib/src/shared/memory/heap_graph_loader.dart b/packages/devtools_app/lib/src/shared/memory/heap_graph_loader.dart index 7a9bedbe6b1..e2dea14be25 100644 --- a/packages/devtools_app/lib/src/shared/memory/heap_graph_loader.dart +++ b/packages/devtools_app/lib/src/shared/memory/heap_graph_loader.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'package:file_selector/file_selector.dart'; +import 'package:meta/meta.dart'; import 'package:vm_service/vm_service.dart'; import '../../screens/memory/shared/primitives/memory_timeline.dart'; @@ -34,6 +35,7 @@ class HeapGraphLoaderRuntime extends HeapGraphLoader { class HeapGraphLoaderFile implements HeapGraphLoader { HeapGraphLoaderFile(this.file); + @visibleForTesting HeapGraphLoaderFile.fromPath(String path) : file = XFile(path); final XFile file; diff --git a/packages/devtools_app/lib/src/shared/memory/retaining_path.dart b/packages/devtools_app/lib/src/shared/memory/retaining_path.dart index b9e7d40e9be..9e68390a9fc 100644 --- a/packages/devtools_app/lib/src/shared/memory/retaining_path.dart +++ b/packages/devtools_app/lib/src/shared/memory/retaining_path.dart @@ -3,7 +3,7 @@ // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; import 'package:vm_service/vm_service.dart'; import '../primitives/utils.dart'; @@ -17,12 +17,15 @@ bool Function(List? list1, List? list2) _listEquality = @visibleForTesting class DebugRetainingPathUsage { /// Path is expected to be constructed for each object. + // ignore: unused-code, TODO(https://github.com/flutter/devtools/issues/9907) false positive. int constructed = 0; /// Only unique paths are stored. + // ignore: unused-code, TODO(https://github.com/flutter/devtools/issues/9907) false positive. int stored = 0; /// Only displayed paths are stringified. + // ignore: unused-code, TODO(https://github.com/flutter/devtools/issues/9907) false positive. int stringified = 0; } @@ -42,12 +45,10 @@ class PathFromRoot { PathFromRoot._( this.path, { @visibleForTesting bool debugOmitClassesInRetainingPath = false, - }) : assert(() { - debugUsage.constructed++; - return true; - }()), - hashCode = path.isEmpty ? _hashOfEmptyPath : Object.hashAll(path), - classes = debugOmitClassesInRetainingPath ? const {} : path.toSet(); + }) : hashCode = path.isEmpty ? _hashOfEmptyPath : Object.hashAll(path), + classes = debugOmitClassesInRetainingPath ? const {} : path.toSet() { + if (kDebugMode) debugUsage.constructed++; + } /// For objects directly referenced from root. const PathFromRoot._empty() @@ -100,11 +101,10 @@ class PathFromRoot { ); instances.add(newInstance); - assert(() { + if (kDebugMode) { debugUsage.stored++; assert(instances.length == debugUsage.stored); - return true; - }()); + } return newInstance; } @@ -208,10 +208,7 @@ class PathFromRoot { required String delimiter, required bool inverted, }) { - assert(() { - debugUsage.stringified++; - return true; - }()); + if (kDebugMode) debugUsage.stringified++; // Trailing separator is here to show object is referenced by root. data = data.joinWith( delimiter, diff --git a/packages/devtools_app/lib/src/shared/preferences/_logging_preferences.dart b/packages/devtools_app/lib/src/shared/preferences/_logging_preferences.dart index 713c6ece0ed..5257ce06fa9 100644 --- a/packages/devtools_app/lib/src/shared/preferences/_logging_preferences.dart +++ b/packages/devtools_app/lib/src/shared/preferences/_logging_preferences.dart @@ -6,8 +6,6 @@ part of 'preferences.dart'; class LoggingPreferencesController extends DisposableController with AutoDisposeControllerMixin { - final retentionLimitTitle = 'Limit for the number of logs retained.'; - /// The number of logs to retain on the logging table. final retentionLimit = ValueNotifier(_defaultRetentionLimit); diff --git a/packages/devtools_app/lib/src/shared/preferences/preferences.dart b/packages/devtools_app/lib/src/shared/preferences/preferences.dart index 403c4e43319..27191349d24 100644 --- a/packages/devtools_app/lib/src/shared/preferences/preferences.dart +++ b/packages/devtools_app/lib/src/shared/preferences/preferences.dart @@ -36,9 +36,6 @@ const _thirdPartyPathSegment = 'third_party'; /// DevTools preferences for experimental features. enum _ExperimentPreferences { - /// Deprecated, we ignore this key in favor of [wasmOptOut]. - wasm, - /// Whether a user has opted out of the dart2wasm experiment. wasmOptOut; @@ -140,13 +137,6 @@ class PreferencesController extends DisposableController setGlobal(PreferencesController, this); } - /// Enables the wasm experiment in storage. - /// - /// This is used to persist the preference across reloads. - Future enableWasmInStorage() async { - await storage.setValue(_ExperimentPreferences.wasm.storageKey, 'true'); - } - Future _initDarkMode() async { final darkModeValue = await storage.getValue( _UiPreferences.darkMode.storageKey, diff --git a/packages/devtools_app/lib/src/shared/primitives/ansi_utils.dart b/packages/devtools_app/lib/src/shared/primitives/ansi_utils.dart index 397c88f20aa..dba6a6ce137 100644 --- a/packages/devtools_app/lib/src/shared/primitives/ansi_utils.dart +++ b/packages/devtools_app/lib/src/shared/primitives/ansi_utils.dart @@ -292,7 +292,6 @@ class _TextPacket { _PacketKind kind; String text = ''; - String url = ''; } /// Chunk of styled text stored in a Dart friendly format. @@ -327,31 +326,4 @@ class StyledText { final List? bgColor; bool get bold => (textStyle & kBold) == kBold; - bool get dim => (textStyle & kDim) == kDim; - bool get italic => (textStyle & kItalic) == kItalic; - bool get underline => (textStyle & kUnderline) == kUnderline; - bool get strikethrough => (textStyle & kStrikethrough) == kStrikethrough; - bool get blink => (textStyle & kBlink) == kBlink; - bool get reverse => (textStyle & kReverse) == kReverse; - bool get invisible => (textStyle & kInvisible) == kInvisible; - - bool get hasStyling => textStyle != 0 || fgColor != null || bgColor != null; - - String get describeStyle { - String hex(int value) => value.toRadixString(16).padLeft(2, '0'); - String color(List rgb) => '${hex(rgb[0])}${hex(rgb[2])}${hex(rgb[2])}'; - - return [ - if (bgColor != null) 'background #${color(bgColor!)}', - if (fgColor != null) 'color #${color(fgColor!)}', - if (bold) 'bold', - if (dim) 'dim', - if (italic) 'italic', - if (underline) 'underline', - if (strikethrough) 'strikethrough', - if (blink) 'blink', - if (reverse) 'reverse', - if (invisible) 'invisible', - ].join(', '); - } } diff --git a/packages/devtools_app/lib/src/shared/primitives/custom_pointer_scroll_view.dart b/packages/devtools_app/lib/src/shared/primitives/custom_pointer_scroll_view.dart index 3794f1c02be..caa711f1baa 100644 --- a/packages/devtools_app/lib/src/shared/primitives/custom_pointer_scroll_view.dart +++ b/packages/devtools_app/lib/src/shared/primitives/custom_pointer_scroll_view.dart @@ -3,6 +3,7 @@ // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd. // ignore_for_file: avoid-explicit-type-declaration, forked code from Flutter framework. +// ignore_for_file: unused-code, forked code from Flutter framework. import 'dart:async'; import 'dart:math' as math; diff --git a/packages/devtools_app/lib/src/shared/primitives/flutter_widgets/linked_scroll_controller.dart b/packages/devtools_app/lib/src/shared/primitives/flutter_widgets/linked_scroll_controller.dart index ad1412178b0..391d7cfacb0 100644 --- a/packages/devtools_app/lib/src/shared/primitives/flutter_widgets/linked_scroll_controller.dart +++ b/packages/devtools_app/lib/src/shared/primitives/flutter_widgets/linked_scroll_controller.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +// ignore_for_file: unused-code, this is forked file, leave untouched. + // This file was originally forked from package:flutter_widgets. Note that the // source may diverge over time. diff --git a/packages/devtools_app/lib/src/shared/primitives/list_queue_value_notifier.dart b/packages/devtools_app/lib/src/shared/primitives/list_queue_value_notifier.dart index afa0bec60aa..5888d132981 100644 --- a/packages/devtools_app/lib/src/shared/primitives/list_queue_value_notifier.dart +++ b/packages/devtools_app/lib/src/shared/primitives/list_queue_value_notifier.dart @@ -2,6 +2,8 @@ // 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. +// ignore_for_file: unused-code, helpful notifer class that will likely be reused. + import 'dart:collection'; import 'package:flutter/foundation.dart'; diff --git a/packages/devtools_app/lib/src/shared/primitives/simple_items.dart b/packages/devtools_app/lib/src/shared/primitives/simple_items.dart index f6de6c579c3..582f0ea022a 100644 --- a/packages/devtools_app/lib/src/shared/primitives/simple_items.dart +++ b/packages/devtools_app/lib/src/shared/primitives/simple_items.dart @@ -30,7 +30,6 @@ const closureName = ''; const anonymousClosureName = ''; const _memoryDocUrl = 'https://docs.flutter.dev/tools/devtools/memory'; -const _consoleDocUrl = 'https://docs.flutter.dev/tools/devtools/console'; const _inspectorDocUrl = 'https://docs.flutter.dev/tools/devtools/inspector'; /// Some links to documentation. @@ -41,7 +40,6 @@ enum DocLinks { profile(_memoryDocUrl, 'profile-memory-tab'), diff(_memoryDocUrl, 'diff-snapshots-tab'), trace(_memoryDocUrl, 'trace-instances-tab'), - console(_consoleDocUrl, null), inspectorPackageDirectories(_inspectorDocUrl, 'package-directories'); const DocLinks(this.url, this.hash); diff --git a/packages/devtools_app/lib/src/shared/primitives/trace_event.dart b/packages/devtools_app/lib/src/shared/primitives/trace_event.dart index 2967fb6a722..105c093ce8d 100644 --- a/packages/devtools_app/lib/src/shared/primitives/trace_event.dart +++ b/packages/devtools_app/lib/src/shared/primitives/trace_event.dart @@ -2,6 +2,8 @@ // 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. +// ignore_for_file: unused-code, this model class follows the Chrome Trace Event format. + /// A single trace event that follows the Chrome Trace Event Format. /// /// See Chrome Trace Event Format documentation: diff --git a/packages/devtools_app/lib/src/shared/primitives/trees.dart b/packages/devtools_app/lib/src/shared/primitives/trees.dart index a86d9720849..d41fc08f97b 100644 --- a/packages/devtools_app/lib/src/shared/primitives/trees.dart +++ b/packages/devtools_app/lib/src/shared/primitives/trees.dart @@ -2,26 +2,21 @@ // 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. +// ignore_for_file: unused-code, retain methods for completeness of TreeNode model class. + import 'dart:collection'; import 'dart:math'; -/// Non-UI specific tree code should live in this file. -/// -/// This file does not have direct dependencies on dart:html and therefore -/// allows for testing to be done on the VM. - -// TODO(kenz): look into consolidating logic between this file and -// ui/trees.dart, which houses generic tree types vs the base classes in this -// file. +// Non-UI specific tree code should live in this file. +// +// This file does not have direct dependencies on dart:html and therefore +// allows for testing to be done on the VM. abstract class TreeNode> { T? parent; final children = []; - // TODO(jacobr) should impact depth. - bool indentChildren = true; - /// Index in `parent.children`. int index = -1; diff --git a/packages/devtools_app/lib/src/shared/primitives/utils.dart b/packages/devtools_app/lib/src/shared/primitives/utils.dart index a1073e882a6..d09c45a3a5b 100644 --- a/packages/devtools_app/lib/src/shared/primitives/utils.dart +++ b/packages/devtools_app/lib/src/shared/primitives/utils.dart @@ -6,7 +6,6 @@ // libraries in this package. import 'dart:async'; -import 'dart:collection'; import 'dart:convert'; import 'dart:math'; @@ -122,20 +121,6 @@ String durationText( return '$durationStr${includeUnit ? ' ${unit.display}' : ''}'; } -T? nullSafeMin(T? a, T? b) { - if (a == null || b == null) { - return a ?? b; - } - return min(a, b); -} - -T? nullSafeMax(T? a, T? b) { - if (a == null || b == null) { - return a ?? b; - } - return max(a, b); -} - double logBase({required int x, required int base}) { return log(x) / log(base); } @@ -145,20 +130,6 @@ int log2(num x) => logBase(x: x.floor(), base: 2).floor(); int roundToNearestPow10(int x) => pow(10, logBase(x: x, base: 10).ceil()).floor(); -void executeWithDelay( - Duration delay, - void Function() callback, { - bool executeNow = false, -}) { - if (executeNow || delay.inMilliseconds <= 0) { - callback(); - } else { - Timer(delay, () { - callback(); - }); - } -} - Future delayToReleaseUiThread({int micros = 0}) async { // Even with a delay of 0 microseconds, awaiting this delay is enough to free // the UI thread to update the UI. @@ -201,39 +172,6 @@ Future timeout(Future operation, int timeoutMillis) => ), ]); -String longestFittingSubstring( - String originalText, - num maxWidth, - List asciiMeasurements, - num Function(int value) slowMeasureFallback, -) { - if (originalText.isEmpty) return originalText; - - final runes = originalText.runes.toList(); - - num currentWidth = 0; - - int i = 0; - while (i < runes.length) { - final rune = runes[i]; - final charWidth = rune < 128 - ? asciiMeasurements[rune] - : slowMeasureFallback(rune); - if (currentWidth + charWidth > maxWidth) { - break; - } - // [currentWidth] is approximate due to ignoring kerning. - currentWidth += charWidth; - i++; - } - - return originalText.substring(0, i); -} - -/// Whether a given code unit is a letter (A-Z or a-z). -bool isLetter(int codeUnit) => - (codeUnit >= 65 && codeUnit <= 90) || (codeUnit >= 97 && codeUnit <= 122); - /// Returns a simplified version of a StackFrame name. /// /// Given an input such as @@ -256,87 +194,6 @@ String getSimpleStackFrameName(String? name) { return newName.split('&').last; } -/// Return a Stream that fires events whenever any of the three given parameter -/// streams fire. -Stream combineStreams(Stream a, Stream b, Stream c) { - late StreamController controller; - - StreamSubscription? asub; - StreamSubscription? bsub; - StreamSubscription? csub; - - controller = StreamController( - onListen: () { - asub = a.listen(controller.add); - bsub = b.listen(controller.add); - csub = c.listen(controller.add); - }, - onCancel: () { - unawaited(asub?.cancel()); - unawaited(bsub?.cancel()); - unawaited(csub?.cancel()); - }, - ); - - return controller.stream; -} - -class Property { - Property(this._value); - - final _changeController = StreamController.broadcast(); - T _value; - - T get value => _value; - - set value(T newValue) { - if (newValue != _value) { - _value = newValue; - _changeController.add(newValue); - } - } - - Stream get onValueChange => _changeController.stream; -} - -/// Batch up calls to the given closure. Repeated calls to [invoke] will -/// overwrite the closure to be called. We'll delay at least [minDelay] before -/// calling the closure, but will not delay more than [maxDelay]. -class DelayedTimer { - DelayedTimer(this.minDelay, this.maxDelay); - - final Duration minDelay; - final Duration maxDelay; - - VoidCallback? _closure; - - Timer? _minTimer; - Timer? _maxTimer; - - void invoke(VoidCallback closure) { - _closure = closure; - - if (_minTimer == null) { - _minTimer = Timer(minDelay, _fire); - _maxTimer = Timer(maxDelay, _fire); - } else { - _minTimer!.cancel(); - _minTimer = Timer(minDelay, _fire); - } - } - - void _fire() { - _minTimer?.cancel(); - _minTimer = null; - - _maxTimer?.cancel(); - _maxTimer = null; - - _closure!(); - _closure = null; - } -} - /// These utilities are ported from the Flutter IntelliJ plugin. /// /// With Dart's terser JSON support, these methods don't provide much value so @@ -355,10 +212,9 @@ class JsonUtils { } } -/// Add pretty print for a JSON payload. -extension JsonMap on Map { - String prettyPrint() => const JsonEncoder.withIndent(' ').convert(this); -} +/// Returns a pretty-printed representation of a JSON payload. +String prettyPrintJson(Object? json) => + const JsonEncoder.withIndent(' ').convert(json); typedef RateLimiterCallback = Future Function(); @@ -574,80 +430,6 @@ double safeDivide( return ifNotFinite; } -/// A change reporter that can be listened to. -/// -/// Unlike [ChangeNotifier], [Reporter] stores listeners in a set. This allows -/// O(1) addition/removal of listeners and O(N) listener dispatch. -/// -/// For small N (~ <20), [ChangeNotifier] implementations can be faster because -/// array access is more efficient than set access. Use [Reporter] instead in -/// cases where N is larger. -/// -/// When disposing, any object with a registered listener should `unregister` -/// itself. -/// -/// Only the object that created this reporter should call [notify]. -class Reporter implements Listenable { - final _listeners = {}; - - /// Adds [callback] to this reporter. - /// - /// If [callback] is already registered to this reporter, nothing will happen. - @override - void addListener(VoidCallback callback) { - _listeners.add(callback); - } - - /// Removes the listener [callback]. - @override - void removeListener(VoidCallback callback) { - _listeners.remove(callback); - } - - /// Whether or not this object has any listeners registered. - bool get hasListeners => _listeners.isNotEmpty; - - /// Notifies all listeners of a change. - /// - /// This does not do any change propagation, so if - /// a notification callback leads to a change in the listeners, - /// only the original listeners will be called. - void notify() { - for (final callback in _listeners.toList()) { - callback(); - } - } - - @override - String toString() => describeIdentity(this); -} - -/// A [Reporter] that notifies when its [value] changes. -/// -/// Similar to [ValueNotifier], but with the same performance -/// benefits as [Reporter]. -/// -/// For small N (~ <20), [ValueNotifier] implementations can be faster because -/// array access is more efficient than set access. Use [ValueReporter] instead -/// in cases where N is larger. -class ValueReporter extends Reporter implements ValueListenable { - ValueReporter(this._value); - - @override - T get value => _value; - - set value(T value) { - if (_value == value) return; - _value = value; - notify(); - } - - T _value; - - @override - String toString() => '${describeIdentity(this)}($value)'; -} - String toStringAsFixed(double num, [int fractionDigit = 1]) { return num.toStringAsFixed(fractionDigit); } @@ -664,8 +446,10 @@ extension SafeListOperations on List { } extension SafeAccess on Iterable { + // ignore: unused-code, false positive "this getter is used but never assigned a value" T? get safeFirst => isNotEmpty ? first : null; + // ignore: unused-code, false positive "this getter is used but never assigned a value" T? get safeLast => isNotEmpty ? last : null; } @@ -707,8 +491,6 @@ class LineRange { int get size => end - begin + 1; - bool contains(num target) => target >= begin && target <= end; - @override String toString() => 'LineRange($begin, $end)'; @@ -763,80 +545,6 @@ class DebugTimingLogger { } } -/// Compute a simple moving average. -/// [averagePeriod] default period is 50 units collected. -/// [ratio] default percentage is 50% range is 0..1 -class MovingAverage { - MovingAverage({ - this.averagePeriod = 50, - this.ratio = 0.5, - List? newDataSet, - }) : assert(ratio >= 0 && ratio <= 1, 'Value ratio $ratio is not 0 to 1.') { - if (newDataSet != null) { - var initialDataSet = newDataSet; - final count = newDataSet.length; - if (count > averagePeriod) { - initialDataSet = newDataSet.sublist(count - averagePeriod); - } - - dataSet.addAll(initialDataSet); - for (final value in dataSet) { - averageSum += value; - } - } - } - - final dataSet = Queue(); - - /// Total collected items in the X axis (time) used to compute moving average. - /// Default 100 periods for memory profiler 1-2 periods / seconds. - final int averagePeriod; - - /// Ratio of first item in dataSet when comparing to last - mean - /// e.g., 2 is 50% (dataSet.first ~/ ratioSpike). - final double ratio; - - /// Sum of total heap used and external heap for unitPeriod. - int averageSum = 0; - - /// Reset moving average data. - void clear() { - dataSet.clear(); - averageSum = 0; - } - - // Update the sum to get a new mean. - void add(int value) { - averageSum += value; - dataSet.add(value); - - // Update dataSet of values to not exceede the period of the moving average - // to compute the normal mean. - if (dataSet.length > averagePeriod) { - averageSum -= dataSet.removeFirst(); - } - } - - double get mean { - final periodRange = min(averagePeriod, dataSet.length); - return periodRange > 0 ? averageSum / periodRange : 0; - } - - /// If the last - mean > ratioSpike% of first value in period we're spiking. - bool hasSpike() { - final first = dataSet.safeFirst ?? 0; - final last = dataSet.safeLast ?? 0; - - return last - mean > (first * ratio); - } - - /// If the mean @ ratioSpike% > last value in period we're dipping. - bool isDipping() { - final last = dataSet.safeLast ?? 0; - return (mean * ratio) > last; - } -} - List textSpansFromAnsi(String input, TextStyle defaultStyle) { final parser = AnsiParser(input); return parser.parse().map((entry) { @@ -1024,20 +732,6 @@ extension ListExtension on List { T get second => this[1]; T get third => this[2]; - - T get fourth => this[3]; - - T get fifth => this[4]; - - List allIndicesWhere(bool Function(T element) test) { - final indices = []; - for (var i = 0; i < length; i++) { - if (test(this[i])) { - indices.add(i); - } - } - return indices; - } } extension NullableListExtension on List? { diff --git a/packages/devtools_app/lib/src/shared/server/server.dart b/packages/devtools_app/lib/src/shared/server/server.dart index 9bf135157d6..8b40cbbf2da 100644 --- a/packages/devtools_app/lib/src/shared/server/server.dart +++ b/packages/devtools_app/lib/src/shared/server/server.dart @@ -165,8 +165,6 @@ void logWarning(Response? response, String apiType) { extension ResponseExtension on Response { bool get statusOk => statusCode == 200; - bool get statusForbidden => statusCode == 403; - bool get statusError => statusCode == 500; } class ServerConnectionStorage implements Storage { diff --git a/packages/devtools_app/lib/src/shared/table/_tree_table.dart b/packages/devtools_app/lib/src/shared/table/_tree_table.dart index 22db562d84c..8630bfb596b 100644 --- a/packages/devtools_app/lib/src/shared/table/_tree_table.dart +++ b/packages/devtools_app/lib/src/shared/table/_tree_table.dart @@ -121,6 +121,7 @@ class TreeTable> extends StatefulWidget { class TreeTableState> extends State> with TickerProviderStateMixin, AutoDisposeMixin { + @visibleForTesting FocusNode? get focusNode => _focusNode; // ignore: dispose-fields, false positive. Disposed via autoDisposeFocusNode. diff --git a/packages/devtools_app/lib/src/shared/ui/colors.dart b/packages/devtools_app/lib/src/shared/ui/colors.dart index 2232fd6d282..a330946505b 100644 --- a/packages/devtools_app/lib/src/shared/ui/colors.dart +++ b/packages/devtools_app/lib/src/shared/ui/colors.dart @@ -12,19 +12,8 @@ import 'utils.dart'; const mainUiColor = Color(0xFF88B1DE); const mainRasterColor = Color(0xFF2C5DAA); -const mainUnknownColor = Color(0xFFCAB8E9); const mainAsyncColor = Color(0xFF80CBC4); -final uiColorPalette = [ - const ColorPair(background: mainUiColor, foreground: Colors.black), - const ColorPair(background: Color(0xFF6793CD), foreground: Colors.black), -]; - -final rasterColorPalette = [ - const ColorPair(background: mainRasterColor, foreground: Colors.white), - const ColorPair(background: Color(0xFF386EB6), foreground: Colors.white), -]; - // TODO(jacobr): merge this with other color scheme extensions. extension FlameChartColorScheme on ColorScheme { Color get selectedFrameBackgroundColor => @@ -34,18 +23,6 @@ extension FlameChartColorScheme on ColorScheme { isLight ? Colors.black54 : const Color.fromARGB(255, 200, 200, 200); } -// Teal 200, 400 - see https://material.io/design/color/#tools-for-picking-colors. -const asyncColorPalette = [ - ColorPair(background: mainAsyncColor, foreground: Colors.black), - ColorPair(background: Color(0xFF26A69A), foreground: Colors.black), -]; - -// Slight variation on Deep purple 100, 300 - see https://material.io/design/color/#tools-for-picking-colors. -const unknownColorPalette = [ - ColorPair(background: mainUnknownColor, foreground: Colors.black), - ColorPair(background: Color(0xFF9D84CA), foreground: Colors.black), -]; - const uiJankColor = Color(0xFFF5846B); const rasterJankColor = Color(0xFFC3595A); const shaderCompilationColor = ColorPair( @@ -111,7 +88,6 @@ extension DevToolsColorExtension on ColorScheme { Color get grey => const Color.fromARGB(255, 128, 128, 128); Color get green => isLight ? const Color(0xFF006B5F) : const Color(0xFF54DBC8); - Color get overlayShadowColor => const Color.fromRGBO(0, 0, 0, 0.5); // Deep link header is slightly darker than the default surface color. See // comment at: https://github.com/flutter/devtools/pull/7443/files#r1538361768 Color get deeplinkTableHeaderColor => surface.darken(); diff --git a/packages/devtools_app/lib/src/shared/ui/common_widgets.dart b/packages/devtools_app/lib/src/shared/ui/common_widgets.dart index dda95c8ad5d..d26a6cb4487 100644 --- a/packages/devtools_app/lib/src/shared/ui/common_widgets.dart +++ b/packages/devtools_app/lib/src/shared/ui/common_widgets.dart @@ -21,7 +21,6 @@ import '../diagnostics/dart_object_node.dart'; import '../diagnostics/tree_builder.dart'; import '../framework/routing.dart'; import '../globals.dart'; -import '../primitives/flutter_widgets/linked_scroll_controller.dart'; import '../primitives/utils.dart'; import '../utils/utils.dart'; @@ -33,36 +32,6 @@ void setAssumedMonospaceCharacterWidth(double width) { _assumedMonospaceCharacterWidth = width; } -/// Creates a semibold version of [style]. -TextStyle semibold(TextStyle style) => - style.copyWith(fontWeight: FontWeight.w600); - -/// Creates a version of [style] that uses the primary color of [context]. -/// -/// When the app is in dark mode, it instead uses the accent color. -TextStyle primaryColor(TextStyle style, BuildContext context) { - final theme = Theme.of(context); - return style.copyWith( - color: (theme.brightness == Brightness.light) - ? theme.primaryColor - : theme.colorScheme.secondary, - fontWeight: FontWeight.w400, - ); -} - -/// Creates a version of [style] that uses the lighter primary color of -/// [context]. -/// -/// In dark mode, the light primary color still has enough contrast to be -/// visible, so we continue to use it. -TextStyle primaryColorLight(TextStyle style, BuildContext context) { - final theme = Theme.of(context); - return style.copyWith( - color: theme.primaryColorLight, - fontWeight: FontWeight.w300, - ); -} - class GaDevToolsButton extends DevToolsButton { GaDevToolsButton({ super.key, @@ -257,52 +226,6 @@ class StartStopRecordingButton extends GaDevToolsButton { final bool recording; } -/// Button to start recording data. -/// -/// * `recording`: Whether recording is in progress. -/// * `minScreenWidthForText`: The minimum width the button can be before the text is -/// omitted. -/// * `labelOverride`: Optional alternative text to use for the button. -/// * `onPressed`: The callback to be called upon pressing the button. -class RecordButton extends GaDevToolsButton { - RecordButton({ - super.key, - required bool recording, - required VoidCallback onPressed, - required super.gaScreen, - required super.gaSelection, - super.minScreenWidthForText, - super.tooltip = 'Start recording', - String? labelOverride, - }) : super( - onPressed: recording ? null : onPressed, - icon: Icons.fiber_manual_record, - label: labelOverride ?? 'Record', - ); -} - -/// Button to stop recording data. -/// -/// * `recording`: Whether recording is in progress. -/// * `minScreenWidthForText`: The minimum width the button can be before the text is -/// omitted. -/// * `onPressed`: The callback to be called upon pressing the button. -class StopRecordingButton extends GaDevToolsButton { - StopRecordingButton({ - super.key, - required bool recording, - required VoidCallback? onPressed, - required super.gaScreen, - required super.gaSelection, - super.minScreenWidthForText, - super.tooltip = 'Stop recording', - }) : super( - onPressed: !recording ? null : onPressed, - icon: Icons.stop, - label: 'Stop', - ); -} - class SettingsOutlinedButton extends GaDevToolsButton { SettingsOutlinedButton({ super.key, @@ -474,38 +397,6 @@ class DevToolsSwitch extends StatelessWidget { } } -class ProcessingInfo extends StatelessWidget { - const ProcessingInfo({ - super.key, - required this.progressValue, - required this.processedObject, - }); - - final double? progressValue; - - final String processedObject; - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Processing $processedObject', - style: Theme.of(context).regularTextStyle, - ), - const SizedBox(height: defaultSpacing), - SizedBox( - width: 200.0, - child: LinearProgressIndicator(value: progressValue), - ), - ], - ), - ); - } -} - /// Common button for exiting offline mode. class ExitOfflineButton extends StatelessWidget { const ExitOfflineButton({required this.gaScreen, super.key}); @@ -741,33 +632,6 @@ abstract class ScaffoldAction extends StatelessWidget { } } -/// Button to open related information / documentation. -/// -/// [tooltip] specifies the hover text for the button. -/// [link] is the link that should be opened when the button is clicked. -class InformationButton extends StatelessWidget { - const InformationButton({ - super.key, - required this.tooltip, - required this.link, - }); - - final String tooltip; - - final String link; - - @override - Widget build(BuildContext context) { - return Tooltip( - message: tooltip, - child: IconButton( - icon: const Icon(Icons.help_outline), - onPressed: () async => await launchUrlWithErrorHandling(link), - ), - ); - } -} - class OutlinedRowGroup extends StatelessWidget { const OutlinedRowGroup({super.key, required this.children, this.borderColor}); @@ -812,29 +676,6 @@ class ThickDivider extends StatelessWidget { } } -BoxDecoration roundedBorderDecoration(BuildContext context) => BoxDecoration( - border: Border.all(color: Theme.of(context).focusColor), - borderRadius: defaultBorderRadius, -); - -class LeftBorder extends StatelessWidget { - const LeftBorder({super.key, this.child}); - - final Widget? child; - - @override - Widget build(BuildContext context) { - final leftBorder = Border( - left: BorderSide(color: Theme.of(context).focusColor), - ); - - return Container( - decoration: BoxDecoration(border: leftBorder), - child: child, - ); - } -} - /// The golden ratio. /// /// Makes for nice-looking rectangles. @@ -882,39 +723,6 @@ class CenteredCircularProgressIndicator extends StatelessWidget { } } -/// An extension on [LinkedScrollControllerGroup] to facilitate having the -/// scrolling widgets auto scroll to the bottom on new content. -/// -/// This extension serves the same function as the [ScrollControllerAutoScroll] -/// extension above, but we need to implement these methods again as an -/// extension on [LinkedScrollControllerGroup] because individual -/// [ScrollController]s are intentionally inaccessible from -/// [LinkedScrollControllerGroup]. -extension LinkedScrollControllerGroupExtension on LinkedScrollControllerGroup { - bool get atScrollBottom { - final pos = position; - return pos.pixels == pos.maxScrollExtent; - } - - /// Scroll the content to the bottom using the app's default animation - /// duration and curve.. - void autoScrollToBottom() async { - await animateTo( - position.maxScrollExtent, - duration: rapidDuration, - curve: defaultCurve, - ); - - // Scroll again if we've received new content in the interim. - if (hasAttachedControllers) { - final pos = position; - if (pos.pixels != pos.maxScrollExtent) { - jumpTo(pos.maxScrollExtent); - } - } - } -} - class BreadcrumbNavigator extends StatelessWidget { const BreadcrumbNavigator.builder({ super.key, @@ -1101,7 +909,6 @@ class JsonViewer extends StatefulWidget { class _JsonViewerState extends State { late Future _initializeTree; late DartObjectNode variable; - static const jsonEncoder = JsonEncoder.withIndent(' '); Future _buildAndExpand(DartObjectNode variable) async { // Build the root node @@ -1237,14 +1044,14 @@ class _JsonViewerState extends State { String copyJsonData(DartObjectNode copiedVariable) { // Check if service connection is active if (serviceConnection.serviceManager.connectedState.value.connected) { - return jsonEncoder.convert( + return prettyPrintJson( serviceConnection.serviceManager.service!.fakeServiceCache .instanceToJson(copiedVariable.value as Instance), ); } // Directly convert object to JSON if not connected - return const JsonEncoder.withIndent(' ').convert(copiedVariable.value); + return prettyPrintJson(copiedVariable.value); } } @@ -1689,117 +1496,6 @@ class CheckboxSetting extends StatelessWidget { } } -/// A widget that represents a switch setting and automatically updates for -/// value changes to [notifier]. -class SwitchSetting extends StatelessWidget { - const SwitchSetting({ - super.key, - required this.notifier, - required this.title, - this.tooltip, - this.onChanged, - this.gaScreen, - this.gaItem, - this.activeColor, - this.inactiveColor, - this.minScreenWidthForText, - }); - - final ValueNotifier notifier; - - final String title; - - final String? tooltip; - - final void Function(bool newValue)? onChanged; - - final String? gaScreen; - - final String? gaItem; - - final Color? activeColor; - - final Color? inactiveColor; - - final double? minScreenWidthForText; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - return maybeWrapWithTooltip( - tooltip: tooltip, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (isScreenWiderThan(context, minScreenWidthForText)) - Flexible( - child: RichText( - overflow: TextOverflow.visible, - maxLines: 3, - text: TextSpan(text: title, style: theme.regularTextStyle), - ), - ), - NotifierSwitch( - padding: const EdgeInsets.only(left: borderPadding), - activeColor: activeColor, - inactiveColor: inactiveColor, - notifier: notifier, - onChanged: (bool? value) { - final gaScreen = this.gaScreen; - final gaItem = this.gaItem; - if (gaScreen != null && gaItem != null) { - ga.select(gaScreen, '$gaItem-$value'); - } - final onChanged = this.onChanged; - if (value != null) { - onChanged?.call(value); - } - }, - ), - ], - ), - ); - } -} - -class PubWarningText extends StatelessWidget { - const PubWarningText({super.key}); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final isFlutterApp = - serviceConnection.serviceManager.connectedApp!.isFlutterAppNow == true; - final sdkName = isFlutterApp ? 'Flutter' : 'Dart'; - final minSdkVersion = isFlutterApp ? '2.8.0' : '2.15.0'; - return SelectionArea( - child: Text.rich( - TextSpan( - text: - 'Warning: you should no longer be launching DevTools from' - ' pub.\n\n', - style: theme.subtleTextStyle.copyWith(color: theme.colorScheme.error), - children: [ - TextSpan( - text: - 'DevTools version 2.8.0 will be the last version to ' - 'be shipped on pub. As of $sdkName\nversion >= ' - '$minSdkVersion, DevTools should be launched by running ' - 'the ', - style: theme.subtleTextStyle, - ), - TextSpan( - text: '`dart devtools`', - style: theme.subtleFixedFontStyle, - ), - TextSpan(text: '\ncommand.', style: theme.subtleTextStyle), - ], - ), - ), - ); - } -} - class BlinkingIcon extends StatefulWidget { const BlinkingIcon({ super.key, diff --git a/packages/devtools_app/lib/src/shared/ui/filter.dart b/packages/devtools_app/lib/src/shared/ui/filter.dart index f4a517fd248..7ec4eacda1a 100644 --- a/packages/devtools_app/lib/src/shared/ui/filter.dart +++ b/packages/devtools_app/lib/src/shared/ui/filter.dart @@ -169,6 +169,7 @@ mixin FilterControllerMixin on DisposableController queryFilterArgs.forEach((key, value) => value.reset()); } + @visibleForTesting void resetFilter() { _resetToDefaultFilter(); _activeFilter.value = Filter( diff --git a/packages/devtools_app/lib/src/shared/ui/icons.dart b/packages/devtools_app/lib/src/shared/ui/icons.dart index 9feaa28877e..543b0cb5d9b 100644 --- a/packages/devtools_app/lib/src/shared/ui/icons.dart +++ b/packages/devtools_app/lib/src/shared/ui/icons.dart @@ -16,40 +16,6 @@ import 'package:flutter/material.dart'; import '../../screens/inspector/layout_explorer/ui/widgets_theme.dart'; import 'colors.dart'; -class CustomIcon extends StatelessWidget { - const CustomIcon({ - super.key, - required this.kind, - required this.text, - this.isAbstract = false, - }); - - final IconKind kind; - final String text; - final bool isAbstract; - - AssetImageIcon get baseIcon => kind.icon; - - @override - Widget build(BuildContext context) { - return SizedBox( - width: baseIcon.width, - height: baseIcon.height, - child: Stack( - alignment: AlignmentDirectional.center, - children: [ - baseIcon, - Text( - text, - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 9.0, color: Color(0xFF231F20)), - ), - ], - ), - ); - } -} - /// An icon with one character class CircleIcon extends StatelessWidget { const CircleIcon({ @@ -87,23 +53,6 @@ class CircleIcon extends StatelessWidget { class CustomIconMaker { final iconCache = {}; - Widget? getCustomIcon( - String fromText, { - IconKind? kind, - bool isAbstract = false, - }) { - final theKind = kind ?? IconKind.classIcon; - if (fromText.isEmpty) { - return null; - } - - final text = fromText[0].toUpperCase(); - final mapKey = '${text}_${theKind.name}_$isAbstract'; - return iconCache.putIfAbsent(mapKey, () { - return CustomIcon(kind: theKind, text: text, isAbstract: isAbstract); - }); - } - Widget? fromWidgetName(String? name) { if (name == null) { return null; @@ -131,10 +80,6 @@ class CustomIconMaker { }); } - CustomIcon fromInfo(String name) { - return getCustomIcon(name, kind: IconKind.info) as CustomIcon; - } - bool isAlphabetic(int char) { return (char < '0'.codeUnitAt(0) || char > '9'.codeUnitAt(0)) && char != '_'.codeUnitAt(0) && @@ -142,41 +87,7 @@ class CustomIconMaker { } } -class IconKind { - const IconKind(this.name, this.icon, [AssetImageIcon? abstractIcon]) - : abstractIcon = abstractIcon ?? icon; - - static IconKind classIcon = const IconKind( - 'class', - AssetImageIcon(asset: 'icons/custom/class.png'), - AssetImageIcon(asset: 'icons/custom/class_abstract.png'), - ); - static IconKind field = const IconKind( - 'fields', - AssetImageIcon(asset: 'icons/custom/fields.png'), - ); - static IconKind interface = const IconKind( - 'interface', - AssetImageIcon(asset: 'icons/custom/interface.png'), - ); - static IconKind method = const IconKind( - 'method', - AssetImageIcon(asset: 'icons/custom/method.png'), - AssetImageIcon(asset: 'icons/custom/method_abstract.png'), - ); - static IconKind property = const IconKind( - 'property', - AssetImageIcon(asset: 'icons/custom/property.png'), - ); - static IconKind info = const IconKind( - 'info', - AssetImageIcon(asset: 'icons/custom/info.png'), - ); - - final String name; - final AssetImageIcon icon; - final AssetImageIcon abstractIcon; -} +const infoIcon = AssetImageIcon(asset: 'icons/custom/info.png'); class ColorIcon extends StatelessWidget { const ColorIcon(this.color, {super.key}); @@ -281,11 +192,4 @@ class FlutterMaterialIcons { class Octicons { static const bug = IconData(61714, fontFamily: 'Octicons'); - static const info = IconData(61778, fontFamily: 'Octicons'); - static const deviceMobile = IconData(61739, fontFamily: 'Octicons'); - static const fileZip = IconData(61757, fontFamily: 'Octicons'); - static const clippy = IconData(61724, fontFamily: 'Octicons'); - static const package = IconData(61812, fontFamily: 'Octicons'); - static const dashboard = IconData(61733, fontFamily: 'Octicons'); - static const pulse = IconData(61823, fontFamily: 'Octicons'); } diff --git a/packages/devtools_app/lib/src/shared/ui/search.dart b/packages/devtools_app/lib/src/shared/ui/search.dart index cce643767ff..573d0e016cc 100644 --- a/packages/devtools_app/lib/src/shared/ui/search.dart +++ b/packages/devtools_app/lib/src/shared/ui/search.dart @@ -25,7 +25,6 @@ import 'common_widgets.dart'; /// Top 10 matches to display in auto-complete overlay. const defaultTopMatchesLimit = 10; -int topMatchesLimit = defaultTopMatchesLimit; final _log = Logger('packages/devtools_app/lib/src/shared/ui/search'); @@ -59,6 +58,7 @@ mixin SearchControllerMixin } String get search => _searchNotifier.value; + @visibleForTesting bool get isSearchInProgress => _searchInProgress.value; final _searchMatches = ValueNotifier>([]); @@ -378,12 +378,6 @@ class AutoCompleteState extends State with AutoDisposeMixin { final areaHeight = offset.dy; final maxAreaForPopup = areaHeight - tileEntryHeight; - // TODO(terry): Scrolling doesn't work so max popup height is also total - // matches to use. - topMatchesLimit = min( - defaultTopMatchesLimit, - (maxAreaForPopup / tileEntryHeight) - 1, // zero based. - ).truncate(); // Total tiles visible. final totalTiles = bottom @@ -533,7 +527,6 @@ class EditingParts { /// Parsing characters looking for valid names e.g., /// [ _ | a..z | A..Z ] [ _ | a..z | A..Z | 0..9 ]+ -const asciiSpace = 32; const ascii0 = 48; const ascii9 = 57; const asciiUnderscore = 95; diff --git a/packages/devtools_app/lib/src/shared/ui/utils.dart b/packages/devtools_app/lib/src/shared/ui/utils.dart index bf82e99d997..56f428f31f9 100644 --- a/packages/devtools_app/lib/src/shared/ui/utils.dart +++ b/packages/devtools_app/lib/src/shared/ui/utils.dart @@ -283,6 +283,7 @@ final class ScreenSize { ScreenSize._({required this.height, required this.width}); + // ignore: unused-code, fundamental part of this class. final MediaSize height; final MediaSize width; diff --git a/packages/devtools_app/lib/src/shared/utils/utils.dart b/packages/devtools_app/lib/src/shared/utils/utils.dart index b19bd582841..2d797672b94 100644 --- a/packages/devtools_app/lib/src/shared/utils/utils.dart +++ b/packages/devtools_app/lib/src/shared/utils/utils.dart @@ -12,6 +12,7 @@ import 'dart:math'; import 'package:devtools_app_shared/service.dart'; import 'package:devtools_app_shared/ui.dart'; import 'package:devtools_app_shared/utils.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -31,10 +32,7 @@ final _log = Logger('lib/src/shared/utils'); /// Logging to debug console only in debug runs. void debugLogger(String message) { - assert(() { - _log.info(message); - return true; - }()); + if (kDebugMode) _log.info(message); } /// Whether DevTools is using a dark theme. @@ -288,6 +286,7 @@ Future launchUrlWithErrorHandling(String url) async { /// /// This class may be helpful when sets of work need to be done over a list, /// while avoiding blocking the UI thread. +// ignore: unused-code, this is a helpful utility, use it where we need it next. class InterruptableChunkWorker { InterruptableChunkWorker({ int chunkSize = _defaultChunkSize, 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 6a7d1ed95be..01d911527e9 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 @@ -125,8 +125,7 @@ void main() { expect(find.byType(CpuProfilerDisabled), findsOneWidget); expect(find.byType(ProfileRecordingInstructions), findsNothing); - expect(find.byType(RecordButton), findsNothing); - expect(find.byType(StopRecordingButton), findsNothing); + expect(find.byType(StartStopRecordingButton), findsNothing); expect(find.byType(ClearButton), findsNothing); expect(find.byType(CpuSamplingRateDropdown), findsNothing); expect(find.byType(OpenSaveButtonGroup), findsNothing); diff --git a/packages/devtools_app/test/shared/ansi_output_test.dart b/packages/devtools_app/test/shared/ansi_output_test.dart index 639593cdf9d..f8f4110097d 100644 --- a/packages/devtools_app/test/shared/ansi_output_test.dart +++ b/packages/devtools_app/test/shared/ansi_output_test.dart @@ -315,3 +315,37 @@ void main() { ); }); } + +extension on StyledText { + bool get dim => (textStyle & StyledText.kDim) == StyledText.kDim; + bool get italic => (textStyle & StyledText.kItalic) == StyledText.kItalic; + bool get underline => + (textStyle & StyledText.kUnderline) == StyledText.kUnderline; + bool get strikethrough => + (textStyle & StyledText.kStrikethrough) == StyledText.kStrikethrough; + bool get blink => (textStyle & StyledText.kBlink) == StyledText.kBlink; + bool get reverse => (textStyle & StyledText.kReverse) == StyledText.kReverse; + bool get invisible => + (textStyle & StyledText.kInvisible) == StyledText.kInvisible; + + bool get hasStyling => textStyle != 0 || fgColor != null || bgColor != null; + + @visibleForTesting + String get describeStyle { + String hex(int value) => value.toRadixString(16).padLeft(2, '0'); + String color(List rgb) => '${hex(rgb[0])}${hex(rgb[2])}${hex(rgb[2])}'; + + return [ + if (bgColor != null) 'background #${color(bgColor!)}', + if (fgColor != null) 'color #${color(fgColor!)}', + if (bold) 'bold', + if (dim) 'dim', + if (italic) 'italic', + if (underline) 'underline', + if (strikethrough) 'strikethrough', + if (blink) 'blink', + if (reverse) 'reverse', + if (invisible) 'invisible', + ].join(', '); + } +} diff --git a/packages/devtools_app/test/shared/primitives/utils_test.dart b/packages/devtools_app/test/shared/primitives/utils_test.dart index 3fe14a5dd13..941165d0443 100644 --- a/packages/devtools_app/test/shared/primitives/utils_test.dart +++ b/packages/devtools_app/test/shared/primitives/utils_test.dart @@ -158,20 +158,6 @@ void main() { }); }); - test('nullSafeMin', () { - expect(nullSafeMin(1, 2), equals(1)); - expect(nullSafeMin(1, null), equals(1)); - expect(nullSafeMin(null, 2), equals(2)); - expect(nullSafeMin(null, null), equals(null)); - }); - - test('nullSafeMin', () { - expect(nullSafeMax(1, 2), equals(2)); - expect(nullSafeMax(1, null), equals(1)); - expect(nullSafeMax(null, 2), equals(2)); - expect(nullSafeMax(null, null), equals(null)); - }); - test('log2', () { expect(log2(1), equals(0)); expect(log2(1.5), equals(0)); @@ -189,47 +175,6 @@ void main() { expect(roundToNearestPow10(6581), equals(10000)); }); - test('executeWithDelay', () async { - const delayMs = 500; - int n = 1; - int start = DateTime.now().millisecondsSinceEpoch; - int? end; - - // Condition n >= 2 is false, so we should execute with a delay. - executeWithDelay(const Duration(milliseconds: 500), () { - n++; - end = DateTime.now().millisecondsSinceEpoch; - }, executeNow: n >= 2); - - expect(n, equals(1)); - expect(end, isNull); - await Future.delayed(const Duration(milliseconds: 250)); - expect(n, equals(1)); - expect(end, isNull); - await Future.delayed(const Duration(milliseconds: 250)); - expect(n, equals(2)); - expect(end, isNotNull); - - // 1000ms is arbitrary. We want to ensure it doesn't run in less time than - // we requested (checked above), but we don't want to be too strict because - // shared CI CPUs can be slow. - const epsilonMs = 1000; - expect((end! - start - delayMs).abs(), lessThan(epsilonMs)); - - // Condition n >= 2 is true, so we should not execute with a delay. - end = null; - start = DateTime.now().millisecondsSinceEpoch; - executeWithDelay(const Duration(milliseconds: 500), () { - n++; - end = DateTime.now().millisecondsSinceEpoch; - }, executeNow: true); - expect(n, equals(3)); - expect(end, isNotNull); - // 400ms is arbitrary. It is less than 500, which is what matters. This - // can be increased if this test starts to flake. - expect(end! - start, lessThan(400)); - }); - test('timeout', () async { int value = 0; Future operation() async { @@ -337,107 +282,6 @@ void main() { expect(formatDateTime(DateTime(2020, 1, 16, 13)), '13:00:00.000'); }); - test('longestFittingSubstring', () { - const asciiStr = 'ComponentElement.performRebuild'; - const nonAsciiStr = 'ԪElement.updateChildԪ'; - num slowMeasureCallback(_) => 100; - - expect( - longestFittingSubstring( - asciiStr, - 0, - asciiMeasurements, - slowMeasureCallback, - ), - equals(''), - ); - expect( - longestFittingSubstring( - asciiStr, - 50, - asciiMeasurements, - slowMeasureCallback, - ), - equals('Compo'), - ); - expect( - longestFittingSubstring( - asciiStr, - 224, - asciiMeasurements, - slowMeasureCallback, - ), - equals('ComponentElement.performRebuild'), - ); - expect( - longestFittingSubstring( - asciiStr, - 300, - asciiMeasurements, - slowMeasureCallback, - ), - equals('ComponentElement.performRebuild'), - ); - - expect(nonAsciiStr.codeUnitAt(0), greaterThanOrEqualTo(128)); - expect( - longestFittingSubstring( - nonAsciiStr, - 99, - asciiMeasurements, - slowMeasureCallback, - ), - equals(''), - ); - expect( - longestFittingSubstring( - nonAsciiStr, - 100, - asciiMeasurements, - slowMeasureCallback, - ), - equals('Ԫ'), - ); - expect( - longestFittingSubstring( - nonAsciiStr, - 230, - asciiMeasurements, - slowMeasureCallback, - ), - equals('ԪElement.updateChild'), - ); - expect( - longestFittingSubstring( - nonAsciiStr, - 329, - asciiMeasurements, - slowMeasureCallback, - ), - equals('ԪElement.updateChild'), - ); - expect( - longestFittingSubstring( - nonAsciiStr, - 330, - asciiMeasurements, - slowMeasureCallback, - ), - equals('ԪElement.updateChildԪ'), - ); - }); - - test('isLetter', () { - expect(isLetter('@'.codeUnitAt(0)), isFalse); - expect(isLetter('['.codeUnitAt(0)), isFalse); - expect(isLetter('`'.codeUnitAt(0)), isFalse); - expect(isLetter('{'.codeUnitAt(0)), isFalse); - expect(isLetter('A'.codeUnitAt(0)), isTrue); - expect(isLetter('Z'.codeUnitAt(0)), isTrue); - expect(isLetter('a'.codeUnitAt(0)), isTrue); - expect(isLetter('z'.codeUnitAt(0)), isTrue); - }); - test('getSimpleStackFrameName', () { String name = '_WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&' @@ -509,89 +353,6 @@ void main() { }); }); - group('Reporter', () { - int called = 0; - late Reporter reporter; - void call() { - called++; - } - - setUp(() { - called = 0; - reporter = Reporter(); - }); - test('notifies listeners', () { - expect(reporter.hasListeners, false); - reporter.addListener(call); - expect(called, 0); - expect(reporter.hasListeners, true); - reporter.notify(); - expect(called, 1); - reporter.notify(); - reporter.notify(); - expect(called, 3); - reporter.removeListener(call); - expect(called, 3); - }); - - test('notifies multiple listeners', () { - reporter.addListener(() => called++); - reporter.addListener(() => called++); - reporter.addListener(() => called++); - reporter.notify(); - expect(called, 3); - // Note that because we passed in anonymous callbacks, there's no way - // to remove them. - }); - - test('deduplicates listeners', () { - reporter.addListener(call); - reporter.addListener(call); - reporter.notify(); - expect(called, 1); - reporter.removeListener(call); - reporter.notify(); - expect(called, 1); - }); - - test('safely removes multiple times', () { - reporter.removeListener(call); - reporter.addListener(call); - reporter.notify(); - expect(called, 1); - reporter.removeListener(call); - reporter.removeListener(call); - reporter.notify(); - expect(called, 1); - }); - }); - - group('ValueReporter', () { - int called = 0; - void call() { - called++; - } - - late ValueReporter reporter; - setUp(() { - reporter = ValueReporter(null); - }); - test('notifies listeners', () { - expect(reporter.hasListeners, false); - reporter.addListener(call); - expect(called, 0); - expect(reporter.hasListeners, true); - reporter.value = 'first call'; - expect(called, 1); - reporter.value = 'second call'; - reporter.value = 'third call'; - expect(called, 3); - reporter.removeListener(call); - reporter.value = 'fourth call'; - expect(called, 3); - }); - }); - group('SafeListOperations', () { test('safeFirst', () { final list = []; @@ -667,506 +428,207 @@ void main() { }); }); - group('MovingAverage', () { - const simpleDataSet = [ - 100, - 200, - 300, - 500, - 1000, - 2000, - 3000, - 4000, - 10000, - 100000, - ]; - - /// Data only has spikes. - const memorySizeDataSet = [ - 190432640, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 201045160, - 198200392, - 200144872, - 210110632, - 234077984, - 229029504, - 229029544, - 231396416, - 240465152, - 303434344, // Spike @ [25] (clear) - 302925712, - 356093472, - 354292096, - 400654120, - 400538848, - 402336872, - 444325760, - 444933104, - 341888120, - 406070376, - 343798216, - 392421072, - 392441080, - 481891656, - 481447920, - 433271776, - 464727280, - 494727280, - 564727280, - 524727280, - 534727280, - 564727280, - 764727280, // Spike @ [48] - 964727280, // Spike @ [49] - 1064727280, // Spike @ [50] - 1464727280, // Spike @ [51] - 2264727280, // Spike @ [52] - 2500000000, // Spike @ [53] - ]; - - /// Data has 5 spikes and 3 dips. - const dipsSpikesDataSet = [ - 190432640, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 190443808, - 5500000, // Dips @ [12] - 5600000, - 7443808, - 9043808, - 11045160, - 49800392, // Spikes @ [17] - 60144872, - 210110632, // Spikes @ [19] - 234077984, - 229029504, - 229029544, - 194000000, - 80000000, // Dips @ [24] - 100000000, - 150000000, - 240465152, // Spike @ [27] - 303434344, - 302925712, - 356093472, - 354292096, - 400654120, - 400538848, - 402336872, - 444325760, - 444933104, - 341888120, - 406070376, - 343798216, - 392421072, - 392441080, - 481891656, - 3000000, // Dips @ [43] - 3100000, - 3200000, - 330000000, // Spike @ [46] - 330000000, - 330000000, - 340000000, - 340000000, - 340000000, - 964727280, - 1064727280, - 1464727280, - 2264727280, // Spike @ [52] - 2500000000, - ]; - - void checkNewItemsAddedToDataSet(MovingAverage mA) { - mA.add(1000000); - mA.add(2000000); - mA.add(3000000); - expect(mA.dataSet.length, lessThan(mA.averagePeriod)); - expect(mA.mean.toInt(), equals(470853)); - expect(mA.hasSpike(), isTrue); - expect(mA.isDipping(), isFalse); - } - - test('basic MA', () { - // Creation of MovingAverage statically. - final simpleMA = MovingAverage(newDataSet: simpleDataSet); - expect(simpleMA.dataSet.length, lessThan(simpleMA.averagePeriod)); - expect(simpleMA.mean.toInt(), equals(12110)); - checkNewItemsAddedToDataSet(simpleMA); - - simpleMA.clear(); - expect(simpleMA.mean, equals(0)); - - // Dynamically add data to MovingAverage data set. - for (int i = 0; i < simpleDataSet.length; i++) { - simpleMA.add(simpleDataSet[i]); - } - // Should be identical to static one from above. - expect(simpleMA.mean.toInt(), equals(12110)); - checkNewItemsAddedToDataSet(simpleMA); - }); - - test('normal static MA', () { - // Creation of MovingAverage statically. - final mA = MovingAverage(newDataSet: memorySizeDataSet); - // Mean only calculated on last averagePeriod entries (50 default). - expect(mA.mean.toInt(), equals(462271799)); - expect(mA.dataSet.length, equals(mA.averagePeriod)); - expect(mA.hasSpike(), isTrue); - expect(mA.isDipping(), isFalse); - - mA.clear(); - expect(mA.mean, equals(0)); - expect(mA.dataSet.length, equals(0)); + group('ListExtension', () { + test('joinWith generates correct list', () { + expect([1, 2, 3, 4].joinWith(0), equals([1, 0, 2, 0, 3, 0, 4])); + expect([1].joinWith(0), equals([1])); + expect(['a', 'b'].joinWith('z'), equals(['a', 'z', 'b'])); }); + }); - test('dynamic spikes MA', () { - final mA = MovingAverage(); - - // Dynamically add data to MovingAverage data set. - for (int i = 0; i < 20; i++) { - mA.add(memorySizeDataSet[i]); - expect(mA.hasSpike(), isFalse); - expect(mA.isDipping(), isFalse); - } - expect(mA.mean.toInt(), equals(192829540)); - - for (int i = 20; i < 50; i++) { - mA.add(memorySizeDataSet[i]); - switch (i) { - case 25: - expect(mA.hasSpike(), isTrue); - expect(mA.isDipping(), isFalse); - mA.clear(); - expect(mA.dataSet.length, 0); - break; - case 48: - case 49: - expect(mA.hasSpike(), isTrue); - expect(mA.isDipping(), isFalse); - break; - default: - expect(mA.dataSet.length, i < 25 ? i + 1 : i - 25); - expect(mA.hasSpike(), isFalse); - expect(mA.isDipping(), isFalse); - } - } - expect(mA.mean.toInt(), equals(469047851)); - - expect(mA.dataSet.length, 24); - - for (int i = 50; i < memorySizeDataSet.length; i++) { - mA.add(memorySizeDataSet[i]); - switch (i) { - case 50: - expect(mA.mean.toInt(), equals(492875028)); - expect(mA.hasSpike(), isTrue); - expect(mA.isDipping(), isFalse); - expect(mA.dataSet.length, equals(25)); - break; - case 51: - expect(mA.mean.toInt(), equals(530253961)); - expect(mA.hasSpike(), isTrue); - expect(mA.isDipping(), isFalse); - expect(mA.dataSet.length, equals(26)); - break; - case 52: - expect(mA.mean.toInt(), equals(594493714)); - expect(mA.hasSpike(), isTrue); - expect(mA.isDipping(), isFalse); - expect(mA.dataSet.length, equals(27)); - break; - case 53: - expect(mA.mean.toInt(), equals(662547510)); - expect(mA.hasSpike(), isTrue); - expect(mA.isDipping(), isFalse); - expect(mA.dataSet.length, equals(28)); - break; - default: - expect(false, isTrue); - } - } - - // dataSet was cleared on first spike @ item 25 so - // dataSet only has the remaining 28 entries. - expect(mA.dataSet.length, 28); - expect(mA.mean.toInt(), equals(662547510)); - - mA.clear(); - expect(mA.mean, equals(0)); - expect(mA.dataSet.length, equals(0)); + group('NullableListExtension', () { + test('isNullOrEmpty', () { + List? nullableList; + expect(nullableList.isNullOrEmpty, true); + nullableList = []; + expect(nullableList.isNullOrEmpty, true); + nullableList.add(1); + expect(nullableList.isNullOrEmpty, false); }); + }); - test('dips and spikes MA', () { - final mA = MovingAverage(); - - // Dynamically add data to MovingAverage data set. - for (int i = 0; i < memorySizeDataSet.length; i++) { - mA.add(dipsSpikesDataSet[i]); - switch (i) { - case 12: - case 24: - case 43: - expect(mA.hasSpike(), isFalse); - expect(mA.isDipping(), isTrue); - break; - case 17: - case 19: - case 27: - case 46: - case 52: - expect(mA.hasSpike(), isTrue); - expect(mA.isDipping(), isFalse); - break; - default: - expect(mA.hasSpike(), isFalse); - expect(mA.isDipping(), isFalse); - } - if (mA.hasSpike() || mA.isDipping()) { - mA.clear(); - expect(mA.dataSet.length, 0); - } - } + group('SetExtension', () { + test('containsAny', () { + final test = {1, 2, 3, 4}; + final subSet = {1, 2}; + final disjointSet = {5, 6, 7}; + expect(test.containsAny(test), true); + expect(test.containsAny(subSet), true); + expect(test.containsAny(disjointSet), false); }); + }); - group('ListExtension', () { - test('joinWith generates correct list', () { - expect([1, 2, 3, 4].joinWith(0), equals([1, 0, 2, 0, 3, 0, 4])); - expect([1].joinWith(0), equals([1])); - expect(['a', 'b'].joinWith('z'), equals(['a', 'z', 'b'])); - }); - - test('allIndicesWhere', () { - final list = [1, 2, 1, 2, 3, 4]; - expect(list.allIndicesWhere((element) => element.isEven), [1, 3, 5]); - expect(list.allIndicesWhere((element) => element.isOdd), [0, 2, 4]); - expect(list.allIndicesWhere((element) => element + 2 == 3), [0, 2]); - }); + group('NullableStringExtension', () { + test('isNullOrEmpty', () { + String? str; + expect(str.isNullOrEmpty, isTrue); + str = ''; + expect(str.isNullOrEmpty, isTrue); + str = 'hello'; + expect(str.isNullOrEmpty, isFalse); + str = null; + expect(str.isNullOrEmpty, isTrue); }); + }); - group('NullableListExtension', () { - test('isNullOrEmpty', () { - List? nullableList; - expect(nullableList.isNullOrEmpty, true); - nullableList = []; - expect(nullableList.isNullOrEmpty, true); - nullableList.add(1); - expect(nullableList.isNullOrEmpty, false); - }); + group('StringExtension', () { + test('caseInsensitiveContains', () { + const str = 'This is a test string with a path/to/uri'; + expect(str.caseInsensitiveContains('test'), isTrue); + expect(str.caseInsensitiveContains('with a PATH/'), isTrue); + expect(str.caseInsensitiveContains('THIS IS A'), isTrue); + expect(str.caseInsensitiveContains('not a match'), isFalse); + expect(str.caseInsensitiveContains('test bool'), isFalse); + expect( + str.caseInsensitiveContains(RegExp('is.*path', caseSensitive: false)), + isTrue, + ); + expect( + () => str.caseInsensitiveContains(RegExp('is.*path')), + throwsAssertionError, + ); + expect( + str.caseInsensitiveContains( + RegExp('THIS IS.*TO/uri', caseSensitive: false), + ), + isTrue, + ); + expect( + str.caseInsensitiveContains( + RegExp('this.*does not match', caseSensitive: false), + ), + isFalse, + ); }); - group('SetExtension', () { - test('containsAny', () { - final test = {1, 2, 3, 4}; - final subSet = {1, 2}; - final disjointSet = {5, 6, 7}; - expect(test.containsAny(test), true); - expect(test.containsAny(subSet), true); - expect(test.containsAny(disjointSet), false); - }); - }); + test('caseInsensitiveEquals', () { + const str = 'hello, world!'; + expect(str.caseInsensitiveEquals(str), isTrue); + expect(str.caseInsensitiveEquals('HELLO, WORLD!'), isTrue); + expect(str.caseInsensitiveEquals('hElLo, WoRlD!'), isTrue); + expect(str.caseInsensitiveEquals('hello'), isFalse); + expect(str.caseInsensitiveEquals(''), isFalse); + expect(str.caseInsensitiveEquals(null), isFalse); + expect(''.caseInsensitiveEquals(''), isTrue); + expect(''.caseInsensitiveEquals(null), isFalse); - group('NullableStringExtension', () { - test('isNullOrEmpty', () { - String? str; - expect(str.isNullOrEmpty, isTrue); - str = ''; - expect(str.isNullOrEmpty, isTrue); - str = 'hello'; - expect(str.isNullOrEmpty, isFalse); - str = null; - expect(str.isNullOrEmpty, isTrue); - }); + // Complete match. + expect( + str.caseInsensitiveEquals(RegExp('h.*o.*', caseSensitive: false)), + isTrue, + ); + // Incomplete match. + expect( + str.caseInsensitiveEquals(RegExp('h.*o', caseSensitive: false)), + isFalse, + ); + // No match. + expect( + str.caseInsensitiveEquals( + RegExp('hello.* this does not match', caseSensitive: false), + ), + isFalse, + ); }); - group('StringExtension', () { - test('caseInsensitiveContains', () { - const str = 'This is a test string with a path/to/uri'; - expect(str.caseInsensitiveContains('test'), isTrue); - expect(str.caseInsensitiveContains('with a PATH/'), isTrue); - expect(str.caseInsensitiveContains('THIS IS A'), isTrue); - expect(str.caseInsensitiveContains('not a match'), isFalse); - expect(str.caseInsensitiveContains('test bool'), isFalse); - expect( - str.caseInsensitiveContains(RegExp('is.*path', caseSensitive: false)), - isTrue, - ); - expect( - () => str.caseInsensitiveContains(RegExp('is.*path')), - throwsAssertionError, - ); - expect( - str.caseInsensitiveContains( - RegExp('THIS IS.*TO/uri', caseSensitive: false), - ), - isTrue, - ); - expect( - str.caseInsensitiveContains( - RegExp('this.*does not match', caseSensitive: false), - ), - isFalse, - ); - }); - - test('caseInsensitiveEquals', () { - const str = 'hello, world!'; - expect(str.caseInsensitiveEquals(str), isTrue); - expect(str.caseInsensitiveEquals('HELLO, WORLD!'), isTrue); - expect(str.caseInsensitiveEquals('hElLo, WoRlD!'), isTrue); - expect(str.caseInsensitiveEquals('hello'), isFalse); - expect(str.caseInsensitiveEquals(''), isFalse); - expect(str.caseInsensitiveEquals(null), isFalse); - expect(''.caseInsensitiveEquals(''), isTrue); - expect(''.caseInsensitiveEquals(null), isFalse); - - // Complete match. - expect( - str.caseInsensitiveEquals(RegExp('h.*o.*', caseSensitive: false)), - isTrue, - ); - // Incomplete match. - expect( - str.caseInsensitiveEquals(RegExp('h.*o', caseSensitive: false)), - isFalse, - ); - // No match. - expect( - str.caseInsensitiveEquals( - RegExp('hello.* this does not match', caseSensitive: false), - ), - isFalse, - ); - }); + test('caseInsensitiveAllMatches', () { + const str = 'This is a TEST. Test string is "test"'; + final matches = 'test'.caseInsensitiveAllMatches(str).toList(); + expect(matches.length, equals(3)); - test('caseInsensitiveAllMatches', () { - const str = 'This is a TEST. Test string is "test"'; - final matches = 'test'.caseInsensitiveAllMatches(str).toList(); - expect(matches.length, equals(3)); + // First match: 'TEST' + expect(matches[0].start, equals(10)); + expect(matches[0].end, equals(14)); - // First match: 'TEST' - expect(matches[0].start, equals(10)); - expect(matches[0].end, equals(14)); + // Second match: 'Test' + expect(matches[1].start, equals(16)); + expect(matches[1].end, equals(20)); - // Second match: 'Test' - expect(matches[1].start, equals(16)); - expect(matches[1].end, equals(20)); + // Third match: 'test' + expect(matches[2].start, equals(32)); + expect(matches[2].end, equals(36)); - // Third match: 'test' - expect(matches[2].start, equals(32)); - expect(matches[2].end, equals(36)); + // Dart's allMatches returns 1 char matches when pattern is an empty string + expect( + ''.caseInsensitiveAllMatches('hello world').length, + equals('hello world'.length + 1), + ); + expect('*'.caseInsensitiveAllMatches('hello world'), isEmpty); + expect('test'.caseInsensitiveAllMatches(''), isEmpty); + expect('test'.caseInsensitiveAllMatches(null), isEmpty); + }); + }); - // Dart's allMatches returns 1 char matches when pattern is an empty string - expect( - ''.caseInsensitiveAllMatches('hello world').length, - equals('hello world'.length + 1), - ); - expect('*'.caseInsensitiveAllMatches('hello world'), isEmpty); - expect('test'.caseInsensitiveAllMatches(''), isEmpty); - expect('test'.caseInsensitiveAllMatches(null), isEmpty); - }); + group('BoolExtension', () { + test('boolCompare', () { + expect(true.boolCompare(true), equals(0)); + expect(false.boolCompare(false), equals(0)); + expect(true.boolCompare(false), equals(-1)); + expect(false.boolCompare(true), equals(1)); }); + }); - group('BoolExtension', () { - test('boolCompare', () { - expect(true.boolCompare(true), equals(0)); - expect(false.boolCompare(false), equals(0)); - expect(true.boolCompare(false), equals(-1)); - expect(false.boolCompare(true), equals(1)); - }); + group('subtractMaps', () { + test('subtracts non-null maps', () { + final subtract = {1: 'subtract'}; + final from = {1: 1.0, 2: 2.0}; + _SubtractionResult? elementSubtractor({ + required String? subtract, + required double? from, + }) => _SubtractionResult(subtract: subtract, from: from); + + final result = subtractMaps( + subtract: subtract, + from: from, + subtractor: elementSubtractor, + ); + + expect( + const SetEquality().equals(result.keys.toSet(), {1, 2}), + true, + ); + expect( + result[1], + equals(_SubtractionResult(subtract: 'subtract', from: 1.0)), + ); + expect(result[2], equals(_SubtractionResult(subtract: null, from: 2.0))); }); - group('subtractMaps', () { - test('subtracts non-null maps', () { - final subtract = {1: 'subtract'}; - final from = {1: 1.0, 2: 2.0}; - _SubtractionResult? elementSubtractor({ - required String? subtract, - required double? from, - }) => _SubtractionResult(subtract: subtract, from: from); - - final result = subtractMaps( - subtract: subtract, - from: from, - subtractor: elementSubtractor, - ); + test('subtracts null', () { + final from = {1: 1.0}; + _SubtractionResult? elementSubtractor({ + required String? subtract, + required double? from, + }) => _SubtractionResult(subtract: subtract, from: from); - expect( - const SetEquality().equals(result.keys.toSet(), {1, 2}), - true, - ); - expect( - result[1], - equals(_SubtractionResult(subtract: 'subtract', from: 1.0)), - ); - expect( - result[2], - equals(_SubtractionResult(subtract: null, from: 2.0)), - ); - }); + final result = subtractMaps( + subtract: null, + from: from, + subtractor: elementSubtractor, + ); - test('subtracts null', () { - final from = {1: 1.0}; - _SubtractionResult? elementSubtractor({ - required String? subtract, - required double? from, - }) => _SubtractionResult(subtract: subtract, from: from); - - final result = subtractMaps( - subtract: null, - from: from, - subtractor: elementSubtractor, - ); + expect(const SetEquality().equals(result.keys.toSet(), {1}), true); + expect(result[1], equals(_SubtractionResult(subtract: null, from: 1.0))); + }); - expect(const SetEquality().equals(result.keys.toSet(), {1}), true); - expect( - result[1], - equals(_SubtractionResult(subtract: null, from: 1.0)), - ); - }); + test('subtracts from null', () { + final subtract = {1: 'subtract'}; + _SubtractionResult? elementSubtractor({ + required String? subtract, + required double? from, + }) => _SubtractionResult(subtract: subtract, from: from); - test('subtracts from null', () { - final subtract = {1: 'subtract'}; - _SubtractionResult? elementSubtractor({ - required String? subtract, - required double? from, - }) => _SubtractionResult(subtract: subtract, from: from); - - final result = subtractMaps( - subtract: subtract, - from: null, - subtractor: elementSubtractor, - ); + final result = subtractMaps( + subtract: subtract, + from: null, + subtractor: elementSubtractor, + ); - expect(const SetEquality().equals(result.keys.toSet(), {1}), true); - expect( - result[1], - equals(_SubtractionResult(subtract: 'subtract', from: null)), - ); - }); + expect(const SetEquality().equals(result.keys.toSet(), {1}), true); + expect( + result[1], + equals(_SubtractionResult(subtract: 'subtract', from: null)), + ); }); }); diff --git a/packages/devtools_app/test/shared/ui/common_widgets_test.dart b/packages/devtools_app/test/shared/ui/common_widgets_test.dart index 6b65b52aa4b..c882092ce79 100644 --- a/packages/devtools_app/test/shared/ui/common_widgets_test.dart +++ b/packages/devtools_app/test/shared/ui/common_widgets_test.dart @@ -13,8 +13,6 @@ import 'package:flutter_test/flutter_test.dart'; // TODO(kenz): add tests for other widgets in common_widgets.dart void main() { - const windowSize = Size(1000.0, 1000.0); - setUp(() { setGlobal( DevToolsEnvironmentParameters, @@ -25,41 +23,6 @@ void main() { setGlobal(IdeTheme, IdeTheme()); }); - group('Common widgets', () { - testWidgetsWithWindowSize( - 'processingInfo builds for progressValue', - windowSize, - (WidgetTester tester) async { - await tester.pumpWidget( - wrap( - const ProcessingInfo( - progressValue: 0.0, - processedObject: 'fake object', - ), - ), - ); - - final progressIndicatorFinder = find.byType(LinearProgressIndicator); - LinearProgressIndicator progressIndicator = tester.widget( - progressIndicatorFinder, - ); - - expect(progressIndicator.value, equals(0.0)); - - await tester.pumpWidget( - wrap( - const ProcessingInfo( - progressValue: 0.5, - processedObject: 'fake object', - ), - ), - ); - progressIndicator = tester.widget(progressIndicatorFinder); - expect(progressIndicator.value, equals(0.5)); - }, - ); - }); - group('NotifierCheckbox', () { bool? findCheckboxValue() { final checkboxWidget = diff --git a/packages/devtools_app/test/shared/utils/utils_test.dart b/packages/devtools_app/test/shared/utils/utils_test.dart index b9cbdf7c9ec..ee6eeed1603 100644 --- a/packages/devtools_app/test/shared/utils/utils_test.dart +++ b/packages/devtools_app/test/shared/utils/utils_test.dart @@ -212,6 +212,10 @@ void main() { ); }); + tearDown(() { + worker.dispose(); + }); + test('0 length', () async { final result = await worker.doWork(0); expect(result, true); diff --git a/packages/devtools_app/test/standalone_ui/ide_shared/property_editor/utils_test.dart b/packages/devtools_app/test/standalone_ui/ide_shared/property_editor/utils_test.dart index 8b45772d59b..eec1e4c5843 100644 --- a/packages/devtools_app/test/standalone_ui/ide_shared/property_editor/utils_test.dart +++ b/packages/devtools_app/test/standalone_ui/ide_shared/property_editor/utils_test.dart @@ -91,8 +91,6 @@ void main() { final firstChild = children.first; final secondChild = children.second; final thirdChild = children.third; - final fourthChild = children.fourth; - final fifthChild = children.fifth; expect( text.textSpan?.toPlainText(), @@ -104,10 +102,6 @@ void main() { expect(_hasStyle(secondChild, style: fixedFontStyle), isTrue); expect(thirdChild.toPlainText(), equals(' and ')); expect(_hasStyle(thirdChild, style: regularFontStyle), isTrue); - expect(fourthChild.toPlainText(), equals('some code')); - expect(_hasStyle(fourthChild, style: fixedFontStyle), isTrue); - expect(fifthChild.toPlainText(), equals('.')); - expect(_hasStyle(fifthChild, style: regularFontStyle), isTrue); }); testWidgets('DartDocConverter handles unmatched brackets', (