// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/// @docImport 'dart:io';
///
/// @docImport 'package:flutter/scheduler.dart';
/// @docImport 'package:flutter_driver/flutter_driver.dart';
///
/// @docImport 'binding.dart';
/// @docImport 'finders.dart';
/// @docImport 'matchers.dart';
/// @docImport 'widget_tester.dart';
library;

import 'dart:ui' as ui;
import 'package:clock/clock.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';

import 'event_simulation.dart';
import 'finders.dart' as finders;
import 'test_async_utils.dart';
import 'test_pointer.dart';
import 'tree_traversal.dart';
import 'window.dart';

/// The default drag touch slop used to break up a large drag into multiple
/// smaller moves.
///
/// This value must be greater than [kTouchSlop].
const double kDragSlopDefault = 20.0;

// Finds the end index (exclusive) of the span at `startIndex`, or `endIndex` if
// there are no other spans between `startIndex` and `endIndex`.
// The InlineSpan protocol doesn't expose the length of the span so we'll
// have to iterate through the whole range.
(InlineSpan, int)? _findEndOfSpan(InlineSpan rootSpan, int startIndex, int endIndex) {
  assert(endIndex > startIndex);
  final InlineSpan? subspan = rootSpan.getSpanForPosition(TextPosition(offset: startIndex));
  if (subspan == null) {
    return null;
  }
  int i = startIndex + 1;
  while (i < endIndex && rootSpan.getSpanForPosition(TextPosition(offset: i)) == subspan) {
    i += 1;
  }
  return (subspan, i);
}

// Examples can assume:
// typedef MyWidget = Placeholder;

/// Class that programmatically interacts with the [Semantics] tree.
///
/// Allows for testing of the [Semantics] tree, which is used by assistive
/// technology, search engines, and other analysis software to determine the
/// meaning of an application.
///
/// Should be accessed through [WidgetController.semantics]. If no custom
/// implementation is provided, a default [SemanticsController] will be created.
class SemanticsController {
  /// Creates a [SemanticsController] that uses the given binding. Will be
  /// automatically created as part of instantiating a [WidgetController], but
  /// a custom implementation can be passed via the [WidgetController] constructor.
  SemanticsController._(this._controller);

  static final int _scrollingActions =
      SemanticsAction.scrollUp.index |
      SemanticsAction.scrollDown.index |
      SemanticsAction.scrollLeft.index |
      SemanticsAction.scrollRight.index |
      SemanticsAction.scrollToOffset.index;

  final WidgetController _controller;

  /// Attempts to find the [SemanticsNode] of first result from `finder`.
  ///
  /// If the object identified by the finder doesn't own its semantic node,
  /// this will return the semantics data of the first ancestor with semantics.
  /// The ancestor's semantic data will include the child's as well as
  /// other nodes that have been merged together.
  ///
  /// If the [SemanticsNode] of the object identified by the finder is
  /// force-merged into an ancestor (e.g. via the [MergeSemantics] widget)
  /// the node into which it is merged is returned. That node will include
  /// all the semantics information of the nodes merged into it.
  ///
  /// Will throw a [StateError] if the finder returns more than one element or
  /// if no semantics are found or are not enabled.
  SemanticsNode find(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    final Iterable<Element> candidates = finder.evaluate();
    if (candidates.isEmpty) {
      throw StateError('Finder returned no matching elements.');
    }
    if (candidates.length > 1) {
      throw StateError('Finder returned more than one element.');
    }
    final Element element = candidates.single;
    RenderObject? renderObject = element.findRenderObject();
    SemanticsNode? result = renderObject?.debugSemantics;
    while (renderObject != null && (result == null || result.isMergedIntoParent)) {
      renderObject = renderObject.parent;
      result = renderObject?.debugSemantics;
    }
    if (result == null) {
      throw StateError('No Semantics data found.');
    }
    return result;
  }

  /// Simulates a traversal of the currently visible semantics tree as if by
  /// assistive technologies.
  ///
  /// Starts at the node for `startNode`. If `startNode` is not provided, then
  /// the traversal begins with the first accessible node in the tree. If
  /// `startNode` finds zero elements or more than one element, a [StateError]
  /// will be thrown.
  ///
  /// Ends at the node for `endNode`, inclusive. If `endNode` is not provided,
  /// then the traversal ends with the last accessible node in the currently
  /// available tree. If `endNode` finds zero elements or more than one element,
  /// a [StateError] will be thrown.
  ///
  /// If provided, the nodes for `endNode` and `startNode` must be part of the
  /// same semantics tree, i.e. they must be part of the same view.
  ///
  /// If neither `startNode` or `endNode` is provided, `view` can be provided to
  /// specify the semantics tree to traverse. If `view` is left unspecified,
  /// [WidgetTester.view] is traversed by default.
  ///
  /// Since the order is simulated, edge cases that differ between platforms
  /// (such as how the last visible item in a scrollable list is handled) may be
  /// inconsistent with platform behavior, but are expected to be sufficient for
  /// testing order, availability to assistive technologies, and interactions.
  ///
  /// ## Sample Code
  ///
  /// ```dart
  /// testWidgets('MyWidget', (WidgetTester tester) async {
  ///   await tester.pumpWidget(const MyWidget());
  ///
  ///   expect(
  ///     tester.semantics.simulatedAccessibilityTraversal(),
  ///     containsAllInOrder(<Matcher>[
  ///       isSemantics(label: 'My Widget'),
  ///       isSemantics(label: 'is awesome!', isChecked: true),
  ///     ]),
  ///   );
  /// });
  /// ```
  ///
  /// See also:
  ///
  /// * [isSemantics] and [matchesSemantics], which can be used to match
  ///   against a single node in the traversal.
  /// * [containsAllInOrder], which can be given an [Iterable<Matcher>] to fuzzy
  ///   match the order allowing extra nodes before after and between matching
  ///   parts of the traversal.
  /// * [orderedEquals], which can be given an [Iterable<Matcher>] to exactly
  ///   match the order of the traversal.
  Iterable<SemanticsNode> simulatedAccessibilityTraversal({
    @Deprecated(
      'Use startNode instead. '
      'This method was originally created before semantics finders were available. '
      'Semantics finders avoid edge cases where some nodes are not discoverable by widget finders and should be preferred for semantics testing. '
      'This feature was deprecated after v3.15.0-15.2.pre.',
    )
    finders.FinderBase<Element>? start,
    @Deprecated(
      'Use endNode instead. '
      'This method was originally created before semantics finders were available. '
      'Semantics finders avoid edge cases where some nodes are not discoverable by widget finders and should be preferred for semantics testing. '
      'This feature was deprecated after v3.15.0-15.2.pre.',
    )
    finders.FinderBase<Element>? end,
    finders.FinderBase<SemanticsNode>? startNode,
    finders.FinderBase<SemanticsNode>? endNode,
    FlutterView? view,
  }) {
    TestAsyncUtils.guardSync();
    assert(
      start == null || startNode == null,
      'Cannot provide both start and startNode. Prefer startNode as start is deprecated.',
    );
    assert(
      end == null || endNode == null,
      'Cannot provide both end and endNode. Prefer endNode as end is deprecated.',
    );

    FlutterView? startView;
    if (start != null) {
      startView = _controller.viewOf(start);
      if (view != null && startView != view) {
        throw StateError(
          'The start node is not part of the provided view.\n'
          'Finder: ${start.toString(describeSelf: true)}\n'
          'View of start node: $startView\n'
          'Specified view: $view',
        );
      }
    } else if (startNode != null) {
      final SemanticsOwner owner = startNode.evaluate().single.owner!;
      final RenderView renderView = _controller.binding.renderViews.firstWhere(
        (RenderView render) => render.owner!.semanticsOwner == owner,
      );
      startView = renderView.flutterView;
      if (view != null && startView != view) {
        throw StateError(
          'The start node is not part of the provided view.\n'
          'Finder: ${startNode.toString(describeSelf: true)}\n'
          'View of start node: $startView\n'
          'Specified view: $view',
        );
      }
    }

    FlutterView? endView;
    if (end != null) {
      endView = _controller.viewOf(end);
      if (view != null && endView != view) {
        throw StateError(
          'The end node is not part of the provided view.\n'
          'Finder: ${end.toString(describeSelf: true)}\n'
          'View of end node: $endView\n'
          'Specified view: $view',
        );
      }
    } else if (endNode != null) {
      final SemanticsOwner owner = endNode.evaluate().single.owner!;
      final RenderView renderView = _controller.binding.renderViews.firstWhere(
        (RenderView render) => render.owner!.semanticsOwner == owner,
      );
      endView = renderView.flutterView;
      if (view != null && endView != view) {
        throw StateError(
          'The end node is not part of the provided view.\n'
          'Finder: ${endNode.toString(describeSelf: true)}\n'
          'View of end node: $endView\n'
          'Specified view: $view',
        );
      }
    }

    if (endView != null && startView != null && endView != startView) {
      throw StateError(
        'The start and end node are in different views.\n'
        'Start finder: ${start!.toString(describeSelf: true)}\n'
        'End finder: ${end!.toString(describeSelf: true)}\n'
        'View of start node: $startView\n'
        'View of end node: $endView',
      );
    }

    final FlutterView actualView = view ?? startView ?? endView ?? _controller.view;
    final RenderView renderView = _controller.binding.renderViews.firstWhere(
      (RenderView r) => r.flutterView == actualView,
    );

    final traversal = <SemanticsNode>[];
    _accessibilityTraversal(renderView.owner!.semanticsOwner!.rootSemanticsNode!, traversal);

    // Setting the range
    SemanticsNode? node;
    String? errorString;

    int startIndex;
    if (start != null) {
      node = find(start);
      startIndex = traversal.indexOf(node);
      errorString = start.toString(describeSelf: true);
    } else if (startNode != null) {
      node = startNode.evaluate().single;
      startIndex = traversal.indexOf(node);
      errorString = startNode.toString(describeSelf: true);
    } else {
      startIndex = 0;
    }
    if (startIndex == -1) {
      throw StateError(
        'The expected starting node was not found.\n'
        'Finder: $errorString\n\n'
        'Expected Start Node: $node\n\n'
        'Traversal: [\n  ${traversal.join('\n  ')}\n]',
      );
    }

    int? endIndex;
    if (end != null) {
      node = find(end);
      endIndex = traversal.indexOf(node);
      errorString = end.toString(describeSelf: true);
    } else if (endNode != null) {
      node = endNode.evaluate().single;
      endIndex = traversal.indexOf(node);
      errorString = endNode.toString(describeSelf: true);
    }
    if (endIndex == -1) {
      throw StateError(
        'The expected ending node was not found.\n'
        'Finder: $errorString\n\n'
        'Expected End Node: $node\n\n'
        'Traversal: [\n  ${traversal.join('\n  ')}\n]',
      );
    }
    endIndex ??= traversal.length - 1;

    return traversal.getRange(startIndex, endIndex + 1);
  }

  /// Recursive depth first traversal of the specified `node`, adding nodes
  /// that are important for semantics to the `traversal` list.
  void _accessibilityTraversal(SemanticsNode node, List<SemanticsNode> traversal) {
    if (_isImportantForAccessibility(node)) {
      traversal.add(node);
    }

    final List<SemanticsNode> children = node.debugListChildrenInOrder(
      DebugSemanticsDumpOrder.traversalOrder,
    );
    for (final child in children) {
      _accessibilityTraversal(child, traversal);
    }
  }

  /// Whether or not the node is important for semantics. Should match most cases
  /// on the platforms, but certain edge cases will be inconsistent.
  ///
  /// Based on:
  ///
  /// * [flutter/engine/AccessibilityBridge.java#SemanticsNode.isFocusable()](https://github.com/flutter/flutter/blob/main/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java#L2641)
  /// * [flutter/engine/SemanticsObject.mm#SemanticsObject.isAccessibilityElement](https://github.com/flutter/flutter/blob/main/engine/src/flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm#L449)
  bool _isImportantForAccessibility(SemanticsNode node) {
    if (node.isMergedIntoParent) {
      // If this node is merged, all its information are present on an ancestor
      // node.
      return false;
    }
    final SemanticsData data = node.getSemanticsData();
    // If the node scopes a route, it doesn't matter what other flags/actions it
    // has, it is _not_ important for accessibility, so we short circuit.
    if (data.flagsCollection.scopesRoute) {
      return false;
    }

    final hasNonScrollingAction = data.actions & ~_scrollingActions != 0;
    if (hasNonScrollingAction) {
      return true;
    }

    /// Based on Android's FOCUSABLE_FLAGS. See [flutter/engine/AccessibilityBridge.java](https://github.com/flutter/flutter/blob/main/engine/src/flutter/shell/platform/android/io/flutter/view/AccessibilityBridge.java).
    final bool hasImportantFlag =
        data.flagsCollection.isChecked != ui.CheckedState.none ||
        data.flagsCollection.isToggled != ui.Tristate.none ||
        data.flagsCollection.isEnabled != ui.Tristate.none ||
        data.flagsCollection.isButton ||
        data.flagsCollection.isTextField ||
        data.flagsCollection.isFocused != ui.Tristate.none ||
        data.flagsCollection.isSlider ||
        data.flagsCollection.isInMutuallyExclusiveGroup;

    if (hasImportantFlag) {
      return true;
    }

    final bool hasContent =
        data.label.isNotEmpty ||
        data.value.isNotEmpty ||
        data.hint.isNotEmpty ||
        data.tooltip.isNotEmpty;
    if (hasContent) {
      return true;
    }

    return false;
  }

  /// Performs the given [SemanticsAction] on the [SemanticsNode] found by `finder`.
  ///
  /// If `args` are provided, they will be passed unmodified with the `action`.
  /// The `checkForAction` argument allows for attempting to perform `action` on
  /// `node` even if it doesn't report supporting that action. This is useful
  /// for implicitly supported actions such as [SemanticsAction.showOnScreen].
  void performAction(
    finders.FinderBase<SemanticsNode> finder,
    SemanticsAction action, {
    Object? args,
    bool checkForAction = true,
  }) {
    final SemanticsNode node = finder.evaluate().single;
    if (checkForAction && !node.getSemanticsData().hasAction(action)) {
      throw StateError(
        'The given node does not support $action. If the action is implicitly '
        'supported or an unsupported action is being tested for this node, '
        'set `checkForAction` to false.\n'
        'Node: $node',
      );
    }

    node.owner!.performAction(node.id, action, args);
  }

  /// Performs a [SemanticsAction.tap] action on the [SemanticsNode] found
  /// by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.tap].
  void tap(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.tap);
  }

  /// Performs a [SemanticsAction.longPress] action on the [SemanticsNode] found
  /// by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.longPress].
  void longPress(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.longPress);
  }

  /// Performs a [SemanticsAction.scrollLeft] action on the [SemanticsNode]
  /// found by `scrollable` or the first scrollable node in the default
  /// semantics tree if no `scrollable` is provided.
  ///
  /// Throws a [StateError] if:
  /// * The given `scrollable` returns zero or more than one result.
  /// * The [SemanticsNode] found with `scrollable` does not support
  ///   [SemanticsAction.scrollLeft].
  void scrollLeft({finders.FinderBase<SemanticsNode>? scrollable}) {
    performAction(scrollable ?? finders.find.semantics.scrollable(), SemanticsAction.scrollLeft);
  }

  /// Performs a [SemanticsAction.scrollRight] action on the [SemanticsNode]
  /// found by `scrollable` or the first scrollable node in the default
  /// semantics tree if no `scrollable` is provided.
  ///
  /// Throws a [StateError] if:
  /// * The given `scrollable` returns zero or more than one result.
  /// * The [SemanticsNode] found with `scrollable` does not support
  ///   [SemanticsAction.scrollRight].
  void scrollRight({finders.FinderBase<SemanticsNode>? scrollable}) {
    performAction(scrollable ?? finders.find.semantics.scrollable(), SemanticsAction.scrollRight);
  }

  /// Performs a [SemanticsAction.scrollUp] action on the [SemanticsNode] found
  /// by `scrollable` or the first scrollable node in the default semantics
  /// tree if no `scrollable` is provided.
  ///
  /// Throws a [StateError] if:
  /// * The given `scrollable` returns zero or more than one result.
  /// * The [SemanticsNode] found with `scrollable` does not support
  ///   [SemanticsAction.scrollUp].
  void scrollUp({finders.FinderBase<SemanticsNode>? scrollable}) {
    performAction(scrollable ?? finders.find.semantics.scrollable(), SemanticsAction.scrollUp);
  }

  /// Performs a [SemanticsAction.scrollDown] action on the [SemanticsNode]
  /// found by `scrollable` or the first scrollable node in the default
  /// semantics tree if no `scrollable` is provided.
  ///
  /// Throws a [StateError] if:
  /// * The given `scrollable` returns zero or more than one result.
  /// * The [SemanticsNode] found with `scrollable` does not support
  ///   [SemanticsAction.scrollDown].
  void scrollDown({finders.FinderBase<SemanticsNode>? scrollable}) {
    performAction(scrollable ?? finders.find.semantics.scrollable(), SemanticsAction.scrollDown);
  }

  /// Performs a [SemanticsAction.increase] action on the [SemanticsNode]
  /// found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.increase].
  void increase(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.increase);
  }

  /// Performs a [SemanticsAction.decrease] action on the [SemanticsNode]
  /// found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.decrease].
  void decrease(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.decrease);
  }

  /// Performs a [SemanticsAction.showOnScreen] action on the [SemanticsNode]
  /// found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.showOnScreen].
  void showOnScreen(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.showOnScreen, checkForAction: false);
  }

  /// Performs a [SemanticsAction.moveCursorForwardByCharacter] action on the
  /// [SemanticsNode] found by `finder`.
  ///
  /// If `shouldModifySelection` is true, then the cursor will begin or extend
  /// a selection.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.moveCursorForwardByCharacter].
  void moveCursorForwardByCharacter(
    finders.FinderBase<SemanticsNode> finder, {
    bool shouldModifySelection = false,
  }) {
    performAction(
      finder,
      SemanticsAction.moveCursorForwardByCharacter,
      args: shouldModifySelection,
    );
  }

  /// Performs a [SemanticsAction.moveCursorForwardByWord] action on the
  /// [SemanticsNode] found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.moveCursorForwardByWord].
  void moveCursorForwardByWord(
    finders.FinderBase<SemanticsNode> finder, {
    bool shouldModifySelection = false,
  }) {
    performAction(finder, SemanticsAction.moveCursorForwardByWord, args: shouldModifySelection);
  }

  /// Performs a [SemanticsAction.moveCursorBackwardByCharacter] action on the
  /// [SemanticsNode] found by `finder`.
  ///
  /// If `shouldModifySelection` is true, then the cursor will begin or extend
  /// a selection.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.moveCursorBackwardByCharacter].
  void moveCursorBackwardByCharacter(
    finders.FinderBase<SemanticsNode> finder, {
    bool shouldModifySelection = false,
  }) {
    performAction(
      finder,
      SemanticsAction.moveCursorBackwardByCharacter,
      args: shouldModifySelection,
    );
  }

  /// Performs a [SemanticsAction.moveCursorBackwardByWord] action on the
  /// [SemanticsNode] found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.moveCursorBackwardByWord].
  void moveCursorBackwardByWord(
    finders.FinderBase<SemanticsNode> finder, {
    bool shouldModifySelection = false,
  }) {
    performAction(finder, SemanticsAction.moveCursorBackwardByWord, args: shouldModifySelection);
  }

  /// Performs a [SemanticsAction.setText] action on the [SemanticsNode]
  /// found by `finder` using the given `text`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.setText].
  void setText(finders.FinderBase<SemanticsNode> finder, String text) {
    performAction(finder, SemanticsAction.setText, args: text);
  }

  /// Performs a [SemanticsAction.setSelection] action on the [SemanticsNode]
  /// found by `finder`.
  ///
  /// The `base` parameter is the start index of selection, and the `extent`
  /// parameter is the length of the selection. Each value should be limited
  /// between 0 and the length of the found [SemanticsNode]'s `value`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.setSelection].
  void setSelection(
    finders.FinderBase<SemanticsNode> finder, {
    required int base,
    required int extent,
  }) {
    performAction(
      finder,
      SemanticsAction.setSelection,
      args: <String, int>{'base': base, 'extent': extent},
    );
  }

  /// Performs a [SemanticsAction.copy] action on the [SemanticsNode]
  /// found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.copy].
  void copy(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.copy);
  }

  /// Performs a [SemanticsAction.cut] action on the [SemanticsNode]
  /// found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.cut].
  void cut(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.cut);
  }

  /// Performs a [SemanticsAction.paste] action on the [SemanticsNode]
  /// found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.paste].
  void paste(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.paste);
  }

  /// Performs a [SemanticsAction.didGainAccessibilityFocus] action on the
  /// [SemanticsNode] found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.didGainAccessibilityFocus].
  void didGainAccessibilityFocus(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.didGainAccessibilityFocus);
  }

  /// Performs a [SemanticsAction.didLoseAccessibilityFocus] action on the
  /// [SemanticsNode] found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.didLoseAccessibilityFocus].
  void didLoseAccessibilityFocus(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.didLoseAccessibilityFocus);
  }

  /// Performs a [SemanticsAction.customAction] action on the
  /// [SemanticsNode] found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.customAction].
  void customAction(finders.FinderBase<SemanticsNode> finder, CustomSemanticsAction action) {
    performAction(
      finder,
      SemanticsAction.customAction,
      args: CustomSemanticsAction.getIdentifier(action),
    );
  }

  /// Performs a [SemanticsAction.dismiss] action on the [SemanticsNode]
  /// found by `finder`.
  ///
  /// Throws a [StateError] if:
  /// * The given `finder` returns zero or more than one result.
  /// * The [SemanticsNode] found with `finder` does not support
  ///   [SemanticsAction.dismiss].
  void dismiss(finders.FinderBase<SemanticsNode> finder) {
    performAction(finder, SemanticsAction.dismiss);
  }
}

/// Class that programmatically interacts with widgets.
///
/// For a variant of this class suited specifically for unit tests, see
/// [WidgetTester]. For one suitable for live tests on a device, consider
/// [LiveWidgetController].
///
/// Concrete subclasses must implement the [pump] method.
abstract class WidgetController {
  /// Creates a widget controller that uses the given binding.
  WidgetController(this.binding);

  /// A reference to the current instance of the binding.
  final WidgetsBinding binding;

  /// The [TestPlatformDispatcher] that is being used in this test.
  ///
  /// This will be injected into the framework such that calls to
  /// [WidgetsBinding.platformDispatcher] will use this. This allows
  /// users to change platform specific properties for testing.
  ///
  /// See also:
  ///
  ///   * [TestFlutterView] which allows changing view specific properties
  ///     for testing
  ///   * [view] and [viewOf] which are used to find
  ///     [TestFlutterView]s from the widget tree
  TestPlatformDispatcher get platformDispatcher =>
      binding.platformDispatcher as TestPlatformDispatcher;

  /// The [TestFlutterView] provided by default when testing with
  /// [WidgetTester.pumpWidget].
  ///
  /// If the test uses multiple views, this will return the view that is painted
  /// into by [WidgetTester.pumpWidget]. If a different view needs to be
  /// accessed use [viewOf] to ensure that the view related to the widget being
  /// evaluated is the one that gets updated.
  ///
  /// See also:
  ///
  ///   * [viewOf], which can find a [TestFlutterView] related to a given finder.
  ///     This is how to modify view properties for testing when dealing with
  ///     multiple views.
  TestFlutterView get view => platformDispatcher.implicitView!;

  /// Provides access to a [SemanticsController] for testing anything related to
  /// the [Semantics] tree.
  ///
  /// Assistive technologies, search engines, and other analysis tools all make
  /// use of the [Semantics] tree to determine the meaning of an application.
  /// If semantics has been disabled for the test, this will throw a [StateError].
  SemanticsController get semantics {
    if (!binding.semanticsEnabled) {
      throw StateError(
        'Semantics are not enabled. Enable them by passing '
        '`semanticsEnabled: true` to `testWidgets`, or by manually creating a '
        '`SemanticsHandle` with `WidgetController.ensureSemantics()`.',
      );
    }

    return _semantics;
  }

  late final SemanticsController _semantics = SemanticsController._(this);

  // FINDER API

  // TODO(ianh): verify that the return values are of type T and throw
  // a good message otherwise, in all the generic methods below

  /// Finds the [TestFlutterView] that is the closest ancestor of the widget
  /// found by [finder].
  ///
  /// [TestFlutterView] can be used to modify view specific properties for testing.
  ///
  /// See also:
  ///
  ///   * [view] which returns the [TestFlutterView] used when only a single
  ///     view is being used.
  TestFlutterView viewOf(finders.FinderBase<Element> finder) {
    return _viewOf(finder) as TestFlutterView;
  }

  FlutterView _viewOf(finders.FinderBase<Element> finder) {
    final FlutterView? view = _maybeViewOf(finder);
    if (view == null) {
      throw StateError(
        'No FlutterView ancestor found for finder: '
        '${finder.toString(describeSelf: true)}',
      );
    }
    return view;
  }

  FlutterView? _maybeViewOf(finders.FinderBase<Element> finder) {
    final Iterable<View> views = widgetList<View>(
      finders.find.ancestor(of: finder, matching: finders.find.byType(View)),
    );
    if (views.isEmpty) {
      return null;
    }
    return views.first.view;
  }

  /// Checks if `finder` exists in the tree.
  bool any(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().isNotEmpty;
  }

  /// All widgets currently in the widget tree (lazy pre-order traversal).
  ///
  /// Can contain duplicates, since widgets can be used in multiple
  /// places in the widget tree.
  Iterable<Widget> get allWidgets {
    TestAsyncUtils.guardSync();
    return allElements.map<Widget>((Element element) => element.widget);
  }

  /// The matching widget in the widget tree.
  ///
  /// Throws a [StateError] if `finder` is empty or matches more than
  /// one widget.
  ///
  /// * Use [firstWidget] if you expect to match several widgets but only want the first.
  /// * Use [widgetList] if you expect to match several widgets and want all of them.
  T widget<T extends Widget>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().single.widget as T;
  }

  /// The first matching widget according to a depth-first pre-order
  /// traversal of the widget tree.
  ///
  /// Throws a [StateError] if `finder` is empty.
  ///
  /// * Use [widget] if you only expect to match one widget.
  T firstWidget<T extends Widget>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().first.widget as T;
  }

  /// The matching widgets in the widget tree.
  ///
  /// * Use [widget] if you only expect to match one widget.
  /// * Use [firstWidget] if you expect to match several but only want the first.
  Iterable<T> widgetList<T extends Widget>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().map<T>((Element element) {
      final result = element.widget as T;
      return result;
    });
  }

  /// Find all layers that are children of the provided [finder].
  ///
  /// The [finder] must match exactly one element.
  Iterable<Layer> layerListOf(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    final Element element = finder.evaluate().single;
    final RenderObject object = element.renderObject!;
    var current = object;
    while (current.debugLayer == null) {
      current = current.parent!;
    }
    final ContainerLayer layer = current.debugLayer!;
    return _walkLayers(layer);
  }

  /// All elements currently in the widget tree (lazy pre-order traversal).
  ///
  /// The returned iterable is lazy. It does not walk the entire widget tree
  /// immediately, but rather a chunk at a time as the iteration progresses
  /// using [Iterator.moveNext].
  Iterable<Element> get allElements {
    TestAsyncUtils.guardSync();
    return collectAllElementsFrom(binding.rootElement!, skipOffstage: false);
  }

  /// The matching element in the widget tree.
  ///
  /// Throws a [StateError] if `finder` is empty or matches more than
  /// one element.
  ///
  /// * Use [firstElement] if you expect to match several elements but only want the first.
  /// * Use [elementList] if you expect to match several elements and want all of them.
  T element<T extends Element>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().single as T;
  }

  /// The first matching element according to a depth-first pre-order
  /// traversal of the widget tree.
  ///
  /// Throws a [StateError] if `finder` is empty.
  ///
  /// * Use [element] if you only expect to match one element.
  T firstElement<T extends Element>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().first as T;
  }

  /// The matching elements in the widget tree.
  ///
  /// * Use [element] if you only expect to match one element.
  /// * Use [firstElement] if you expect to match several but only want the first.
  Iterable<T> elementList<T extends Element>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().cast<T>();
  }

  /// All states currently in the widget tree (lazy pre-order traversal).
  ///
  /// The returned iterable is lazy. It does not walk the entire widget tree
  /// immediately, but rather a chunk at a time as the iteration progresses
  /// using [Iterator.moveNext].
  Iterable<State> get allStates {
    TestAsyncUtils.guardSync();
    return allElements.whereType<StatefulElement>().map<State>(
      (StatefulElement element) => element.state,
    );
  }

  /// The matching state in the widget tree.
  ///
  /// Throws a [StateError] if `finder` is empty, matches more than
  /// one state, or matches a widget that has no state.
  ///
  /// * Use [firstState] if you expect to match several states but only want the first.
  /// * Use [stateList] if you expect to match several states and want all of them.
  T state<T extends State>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return _stateOf<T>(finder.evaluate().single, finder);
  }

  /// The first matching state according to a depth-first pre-order
  /// traversal of the widget tree.
  ///
  /// Throws a [StateError] if `finder` is empty or if the first
  /// matching widget has no state.
  ///
  /// * Use [state] if you only expect to match one state.
  T firstState<T extends State>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return _stateOf<T>(finder.evaluate().first, finder);
  }

  /// The matching states in the widget tree.
  ///
  /// Throws a [StateError] if any of the elements in `finder` match a widget
  /// that has no state.
  ///
  /// * Use [state] if you only expect to match one state.
  /// * Use [firstState] if you expect to match several but only want the first.
  Iterable<T> stateList<T extends State>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().map<T>((Element element) => _stateOf<T>(element, finder));
  }

  T _stateOf<T extends State>(Element element, finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    if (element is StatefulElement) {
      return element.state as T;
    }
    throw StateError(
      'Widget of type ${element.widget.runtimeType}, with ${finder.describeMatch(finders.Plurality.many)}, is not a StatefulWidget.',
    );
  }

  /// Render objects of all the widgets currently in the widget tree
  /// (lazy pre-order traversal).
  ///
  /// This will almost certainly include many duplicates since the
  /// render object of a [StatelessWidget] or [StatefulWidget] is the
  /// render object of its child; only [RenderObjectWidget]s have
  /// their own render object.
  Iterable<RenderObject> get allRenderObjects {
    TestAsyncUtils.guardSync();
    return allElements.map<RenderObject>((Element element) => element.renderObject!);
  }

  /// The render object of the matching widget in the widget tree.
  ///
  /// Throws a [StateError] if `finder` is empty or matches more than
  /// one widget (even if they all have the same render object).
  ///
  /// * Use [firstRenderObject] if you expect to match several render objects but only want the first.
  /// * Use [renderObjectList] if you expect to match several render objects and want all of them.
  T renderObject<T extends RenderObject>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().single.renderObject! as T;
  }

  /// The render object of the first matching widget according to a
  /// depth-first pre-order traversal of the widget tree.
  ///
  /// Throws a [StateError] if `finder` is empty.
  ///
  /// * Use [renderObject] if you only expect to match one render object.
  T firstRenderObject<T extends RenderObject>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().first.renderObject! as T;
  }

  /// The render objects of the matching widgets in the widget tree.
  ///
  /// * Use [renderObject] if you only expect to match one render object.
  /// * Use [firstRenderObject] if you expect to match several but only want the first.
  Iterable<T> renderObjectList<T extends RenderObject>(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    return finder.evaluate().map<T>((Element element) {
      final result = element.renderObject! as T;
      return result;
    });
  }

  /// Returns a list of all the [Layer] objects in the rendering.
  List<Layer> get layers {
    return <Layer>[
      for (final RenderView renderView in binding.renderViews)
        ..._walkLayers(renderView.debugLayer!),
    ];
  }

  Iterable<Layer> _walkLayers(Layer layer) sync* {
    TestAsyncUtils.guardSync();
    yield layer;
    if (layer is ContainerLayer) {
      final ContainerLayer root = layer;
      Layer? child = root.firstChild;
      while (child != null) {
        yield* _walkLayers(child);
        child = child.nextSibling;
      }
    }
  }

  // INTERACTION

  /// Dispatch a pointer down / pointer up sequence at the center of
  /// the given widget, assuming it is exposed.
  ///
  /// {@template flutter.flutter_test.WidgetController.tap.warnIfMissed}
  /// The `warnIfMissed` argument, if true (the default), causes a warning to be
  /// displayed on the console if the specified [Finder] indicates a widget and
  /// location that, were a pointer event to be sent to that location, would not
  /// actually send any events to the widget (e.g. because the widget is
  /// obscured, or the location is off-screen, or the widget is transparent to
  /// pointer events).
  ///
  /// Set the argument to false to silence that warning if you intend to not
  /// actually hit the specified element.
  /// {@endtemplate}
  ///
  /// For example, a test that verifies that tapping a disabled button does not
  /// trigger the button would set `warnIfMissed` to false, because the button
  /// would ignore the tap.
  Future<void> tap(
    finders.FinderBase<Element> finder, {
    int? pointer,
    int buttons = kPrimaryButton,
    bool warnIfMissed = true,
    PointerDeviceKind kind = PointerDeviceKind.touch,
  }) {
    final FlutterView? view = _maybeViewOf(finder);
    return tapAt(
      getCenter(finder, warnIfMissed: warnIfMissed, callee: 'tap'),
      pointer: pointer,
      buttons: buttons,
      kind: kind,
      view: view,
    );
  }

  /// Dispatch a pointer down / pointer up sequence at a hit-testable
  /// [InlineSpan] (typically a [TextSpan]) within the given text range.
  ///
  /// This method performs a more spatially precise tap action on a piece of
  /// static text, than the widget-based [tap] method.
  ///
  /// The given [Finder] must find one and only one matching substring, and the
  /// substring must be hit-testable (meaning, it must not be off-screen, or be
  /// obscured by other widgets, or in a disabled widget). Otherwise this method
  /// throws a [FlutterError].
  ///
  /// If the target substring contains more than one hit-testable [InlineSpan]s,
  /// [tapOnText] taps on one of them, but does not guarantee which.
  ///
  /// The `pointer` and `button` arguments specify [PointerEvent.pointer] and
  /// [PointerEvent.buttons] of the tap event.
  Future<void> tapOnText(
    finders.FinderBase<finders.TextRangeContext> textRangeFinder, {
    int? pointer,
    int buttons = kPrimaryButton,
  }) {
    final Iterable<finders.TextRangeContext> ranges = textRangeFinder.evaluate();
    if (ranges.isEmpty) {
      throw FlutterError(textRangeFinder.toString());
    }
    if (ranges.length > 1) {
      throw FlutterError(
        '$textRangeFinder. The "tapOnText" method needs a single non-empty TextRange.',
      );
    }
    final Offset? tapLocation = _findHitTestableOffsetIn(ranges.single);
    if (tapLocation == null) {
      final finders.TextRangeContext found = textRangeFinder.evaluate().single;
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('Finder specifies a TextRange that can not receive pointer events.'),
        ErrorDescription('The finder used was: ${textRangeFinder.toString(describeSelf: true)}'),
        ErrorDescription(
          'Found a matching substring in a static text widget, within ${found.textRange}.',
        ),
        ErrorDescription(
          'But the "tapOnText" method could not find a hit-testable Offset with in that text range.',
        ),
        found.renderObject.toDiagnosticsNode(
          name: 'The RenderBox of that static text widget was',
          style: DiagnosticsTreeStyle.shallow,
        ),
      ]);
    }
    return tapAt(tapLocation, pointer: pointer, buttons: buttons, view: ranges.single.view.view);
  }

  /// Dispatch a pointer down / pointer up sequence at the given location.
  Future<void> tapAt(
    Offset location, {
    int? pointer,
    int buttons = kPrimaryButton,
    PointerDeviceKind kind = PointerDeviceKind.touch,
    FlutterView? view,
  }) {
    return TestAsyncUtils.guard<void>(() async {
      final TestGesture gesture = await startGesture(
        location,
        pointer: pointer,
        buttons: buttons,
        kind: kind,
        view: view,
      );
      await gesture.up();
    });
  }

  /// Dispatch a pointer down at the center of the given widget, assuming it is
  /// exposed.
  ///
  /// {@macro flutter.flutter_test.WidgetController.tap.warnIfMissed}
  ///
  /// The return value is a [TestGesture] object that can be used to continue the
  /// gesture (e.g. moving the pointer or releasing it).
  ///
  /// See also:
  ///
  ///  * [tap], which presses and releases a pointer at the given location.
  ///  * [longPress], which presses and releases a pointer with a gap in
  ///    between long enough to trigger the long-press gesture.
  Future<TestGesture> press(
    finders.FinderBase<Element> finder, {
    int? pointer,
    int buttons = kPrimaryButton,
    bool warnIfMissed = true,
    PointerDeviceKind kind = PointerDeviceKind.touch,
  }) {
    final FlutterView? view = _maybeViewOf(finder);
    return TestAsyncUtils.guard<TestGesture>(() {
      return startGesture(
        getCenter(finder, warnIfMissed: warnIfMissed, callee: 'press'),
        pointer: pointer,
        buttons: buttons,
        kind: kind,
        view: view,
      );
    });
  }

  /// Dispatch a pointer down / pointer up sequence (with a delay of
  /// [kLongPressTimeout] + [kPressTimeout] between the two events) at the
  /// center of the given widget, assuming it is exposed.
  ///
  /// {@macro flutter.flutter_test.WidgetController.tap.warnIfMissed}
  ///
  /// For example, consider a widget that, when long-pressed, shows an overlay
  /// that obscures the original widget. A test for that widget might first
  /// long-press that widget with `warnIfMissed` at its default value true, then
  /// later verify that long-pressing the same location (using the same finder)
  /// has no effect (since the widget is now obscured), setting `warnIfMissed`
  /// to false on that second call.
  Future<void> longPress(
    finders.FinderBase<Element> finder, {
    int? pointer,
    int buttons = kPrimaryButton,
    bool warnIfMissed = true,
    PointerDeviceKind kind = PointerDeviceKind.touch,
  }) {
    final FlutterView? view = _maybeViewOf(finder);
    return longPressAt(
      getCenter(finder, warnIfMissed: warnIfMissed, callee: 'longPress'),
      pointer: pointer,
      buttons: buttons,
      kind: kind,
      view: view,
    );
  }

  /// Dispatch a pointer down / pointer up sequence at the given location with
  /// a delay of [kLongPressTimeout] + [kPressTimeout] between the two events.
  Future<void> longPressAt(
    Offset location, {
    int? pointer,
    int buttons = kPrimaryButton,
    PointerDeviceKind kind = PointerDeviceKind.touch,
    FlutterView? view,
  }) {
    return TestAsyncUtils.guard<void>(() async {
      final TestGesture gesture = await startGesture(
        location,
        pointer: pointer,
        buttons: buttons,
        kind: kind,
        view: view,
      );
      await pump(kLongPressTimeout + kPressTimeout);
      await gesture.up();
    });
  }

  /// Attempts a fling gesture starting from the center of the given
  /// widget, moving the given distance, reaching the given speed.
  ///
  /// {@macro flutter.flutter_test.WidgetController.tap.warnIfMissed}
  ///
  /// {@template flutter.flutter_test.WidgetController.fling.offset}
  /// The `offset` represents a distance the pointer moves in the global
  /// coordinate system of the screen.
  ///
  /// Positive [Offset.dy] values mean the pointer moves downward. Negative
  /// [Offset.dy] values mean the pointer moves upwards. Accordingly, positive
  /// [Offset.dx] values mean the pointer moves towards the right. Negative
  /// [Offset.dx] values mean the pointer moves towards left.
  /// {@endtemplate}
  ///
  /// {@template flutter.flutter_test.WidgetController.fling}
  /// This can pump frames.
  ///
  /// Exactly 50 pointer events are synthesized.
  ///
  /// The `speed` is in pixels per second in the direction given by `offset`.
  ///
  /// The `offset` and `speed` control the interval between each pointer event.
  /// For example, if the `offset` is 200 pixels down, and the `speed` is 800
  /// pixels per second, the pointer events will be sent for each increment
  /// of 4 pixels (200/50), over 250ms (200/800), meaning events will be sent
  /// every 1.25ms (250/200).
  ///
  /// To make tests more realistic, frames may be pumped during this time (using
  /// calls to [pump]). If the total duration is longer than `frameInterval`,
  /// then one frame is pumped each time that amount of time elapses while
  /// sending events, or each time an event is synthesized, whichever is rarer.
  ///
  /// See [LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive] if the method
  /// is used in a live environment and accurate time control is important.
  ///
  /// The `initialOffset` argument, if non-zero, causes the pointer to first
  /// apply that offset, then pump a delay of `initialOffsetDelay`. This can be
  /// used to simulate a drag followed by a fling, including dragging in the
  /// opposite direction of the fling (e.g. dragging 200 pixels to the right,
  /// then fling to the left over 200 pixels, ending at the exact point that the
  /// drag started).
  /// {@endtemplate}
  ///
  /// A fling is essentially a drag that ends at a particular speed. If you
  /// just want to drag and end without a fling, use [drag].
  Future<void> fling(
    finders.FinderBase<Element> finder,
    Offset offset,
    double speed, {
    int? pointer,
    int buttons = kPrimaryButton,
    Duration frameInterval = const Duration(milliseconds: 16),
    Offset initialOffset = Offset.zero,
    Duration initialOffsetDelay = const Duration(seconds: 1),
    bool warnIfMissed = true,
    PointerDeviceKind deviceKind = PointerDeviceKind.touch,
  }) {
    final FlutterView? view = _maybeViewOf(finder);
    return flingFrom(
      getCenter(finder, warnIfMissed: warnIfMissed, callee: 'fling'),
      offset,
      speed,
      pointer: pointer,
      buttons: buttons,
      frameInterval: frameInterval,
      initialOffset: initialOffset,
      initialOffsetDelay: initialOffsetDelay,
      deviceKind: deviceKind,
      view: view,
    );
  }

  /// Attempts a fling gesture starting from the given location, moving the
  /// given distance, reaching the given speed.
  ///
  /// {@macro flutter.flutter_test.WidgetController.fling}
  ///
  /// A fling is essentially a drag that ends at a particular speed. If you
  /// just want to drag and end without a fling, use [dragFrom].
  Future<void> flingFrom(
    Offset startLocation,
    Offset offset,
    double speed, {
    int? pointer,
    int buttons = kPrimaryButton,
    Duration frameInterval = const Duration(milliseconds: 16),
    Offset initialOffset = Offset.zero,
    Duration initialOffsetDelay = const Duration(seconds: 1),
    PointerDeviceKind deviceKind = PointerDeviceKind.touch,
    FlutterView? view,
  }) {
    assert(offset.distance > 0.0);
    assert(speed > 0.0); // speed is pixels/second
    return TestAsyncUtils.guard<void>(() async {
      final testPointer = TestPointer(pointer ?? _getNextPointer(), deviceKind, null, buttons);
      const kMoveCount =
          50; // Needs to be >= kHistorySize, see _LeastSquaresVelocityTrackerStrategy
      final double timeStampDelta = 1000000.0 * offset.distance / (kMoveCount * speed);
      var timeStamp = 0.0;
      var lastTimeStamp = timeStamp;
      await sendEventToBinding(
        testPointer.down(
          startLocation,
          timeStamp: Duration(microseconds: timeStamp.round()),
          view: view,
        ),
      );
      if (initialOffset.distance > 0.0) {
        await sendEventToBinding(
          testPointer.move(
            startLocation + initialOffset,
            timeStamp: Duration(microseconds: timeStamp.round()),
          ),
        );
        timeStamp += initialOffsetDelay.inMicroseconds;
        await pump(initialOffsetDelay);
      }
      for (var i = 0; i <= kMoveCount; i += 1) {
        final Offset location =
            startLocation + initialOffset + Offset.lerp(Offset.zero, offset, i / kMoveCount)!;
        await sendEventToBinding(
          testPointer.move(
            location,
            timeStamp: Duration(microseconds: timeStamp.round()),
            view: view,
          ),
        );
        timeStamp += timeStampDelta;
        if (timeStamp - lastTimeStamp > frameInterval.inMicroseconds) {
          await pump(Duration(microseconds: (timeStamp - lastTimeStamp).truncate()));
          lastTimeStamp = timeStamp;
        }
      }
      await sendEventToBinding(
        testPointer.up(
          timeStamp: Duration(microseconds: timeStamp.round()),
          view: view,
        ),
      );
    });
  }

  /// Attempts a trackpad fling gesture starting from the center of the given
  /// widget, moving the given distance, reaching the given speed. A trackpad
  /// fling sends PointerPanZoom events instead of a sequence of touch events.
  ///
  /// {@macro flutter.flutter_test.WidgetController.tap.warnIfMissed}
  ///
  /// {@macro flutter.flutter_test.WidgetController.fling}
  ///
  /// A fling is essentially a drag that ends at a particular speed. If you
  /// just want to drag and end without a fling, use [drag].
  Future<void> trackpadFling(
    finders.FinderBase<Element> finder,
    Offset offset,
    double speed, {
    int? pointer,
    int buttons = kPrimaryButton,
    Duration frameInterval = const Duration(milliseconds: 16),
    Offset initialOffset = Offset.zero,
    Duration initialOffsetDelay = const Duration(seconds: 1),
    bool warnIfMissed = true,
  }) {
    final FlutterView? view = _maybeViewOf(finder);
    return trackpadFlingFrom(
      getCenter(finder, warnIfMissed: warnIfMissed, callee: 'fling'),
      offset,
      speed,
      pointer: pointer,
      buttons: buttons,
      frameInterval: frameInterval,
      initialOffset: initialOffset,
      initialOffsetDelay: initialOffsetDelay,
      view: view,
    );
  }

  /// Attempts a fling gesture starting from the given location, moving the
  /// given distance, reaching the given speed. A trackpad fling sends
  /// PointerPanZoom events instead of a sequence of touch events.
  ///
  /// {@macro flutter.flutter_test.WidgetController.fling}
  ///
  /// A fling is essentially a drag that ends at a particular speed. If you
  /// just want to drag and end without a fling, use [dragFrom].
  Future<void> trackpadFlingFrom(
    Offset startLocation,
    Offset offset,
    double speed, {
    int? pointer,
    int buttons = kPrimaryButton,
    Duration frameInterval = const Duration(milliseconds: 16),
    Offset initialOffset = Offset.zero,
    Duration initialOffsetDelay = const Duration(seconds: 1),
    FlutterView? view,
  }) {
    assert(offset.distance > 0.0);
    assert(speed > 0.0); // speed is pixels/second
    return TestAsyncUtils.guard<void>(() async {
      final testPointer = TestPointer(
        pointer ?? _getNextPointer(),
        PointerDeviceKind.trackpad,
        null,
        buttons,
      );
      const kMoveCount =
          50; // Needs to be >= kHistorySize, see _LeastSquaresVelocityTrackerStrategy
      final double timeStampDelta = 1000000.0 * offset.distance / (kMoveCount * speed);
      var timeStamp = 0.0;
      var lastTimeStamp = timeStamp;
      await sendEventToBinding(
        testPointer.panZoomStart(
          startLocation,
          timeStamp: Duration(microseconds: timeStamp.round()),
          view: view,
        ),
      );
      if (initialOffset.distance > 0.0) {
        await sendEventToBinding(
          testPointer.panZoomUpdate(
            startLocation,
            pan: initialOffset,
            timeStamp: Duration(microseconds: timeStamp.round()),
            view: view,
          ),
        );
        timeStamp += initialOffsetDelay.inMicroseconds;
        await pump(initialOffsetDelay);
      }
      for (var i = 0; i <= kMoveCount; i += 1) {
        final Offset pan = initialOffset + Offset.lerp(Offset.zero, offset, i / kMoveCount)!;
        await sendEventToBinding(
          testPointer.panZoomUpdate(
            startLocation,
            pan: pan,
            timeStamp: Duration(microseconds: timeStamp.round()),
            view: view,
          ),
        );
        timeStamp += timeStampDelta;
        if (timeStamp - lastTimeStamp > frameInterval.inMicroseconds) {
          await pump(Duration(microseconds: (timeStamp - lastTimeStamp).truncate()));
          lastTimeStamp = timeStamp;
        }
      }
      await sendEventToBinding(
        testPointer.panZoomEnd(
          timeStamp: Duration(microseconds: timeStamp.round()),
          view: view,
        ),
      );
    });
  }

  /// A simulator of how the framework handles a series of [PointerEvent]s
  /// received from the Flutter engine.
  ///
  /// The [PointerEventRecord.timeDelay] is used as the time delay of the events
  /// injection relative to the starting point of the method call.
  ///
  /// Returns a list of the difference between the real delay time when the
  /// [PointerEventRecord.events] are processed and
  /// [PointerEventRecord.timeDelay].
  /// - For [AutomatedTestWidgetsFlutterBinding] where the clock is fake, the
  ///   return value should be exact zeros.
  /// - For [LiveTestWidgetsFlutterBinding], the values are typically small
  /// positives, meaning the event happens a little later than the set time,
  /// but a very small portion may have a tiny negative value for about tens of
  /// microseconds. This is due to the nature of [Future.delayed].
  ///
  /// The closer the return values are to zero the more faithful it is to the
  /// `records`.
  ///
  /// See [PointerEventRecord].
  Future<List<Duration>> handlePointerEventRecord(List<PointerEventRecord> records);

  /// Called to indicate that there should be a new frame after an optional
  /// delay.
  ///
  /// The frame is pumped after a delay of [duration] if [duration] is not null,
  /// or immediately otherwise.
  ///
  /// This is invoked by [flingFrom], for instance, so that the sequence of
  /// pointer events occurs over time.
  ///
  /// The [WidgetTester] subclass implements this by deferring to the [binding].
  ///
  /// See also:
  ///
  ///  * [SchedulerBinding.endOfFrame], which returns a future that could be
  ///    appropriate to return in the implementation of this method.
  Future<void> pump([Duration duration]);

  /// Repeatedly calls [pump] with the given `duration` until there are no
  /// longer any frames scheduled. This will call [pump] at least once, even if
  /// no frames are scheduled when the function is called, to flush any pending
  /// microtasks which may themselves schedule a frame.
  ///
  /// This essentially waits for all animations to have completed.
  ///
  /// If it takes longer that the given `timeout` to settle, then the test will
  /// fail (this method will throw an exception). In particular, this means that
  /// if there is an infinite animation in progress (for example, if there is an
  /// indeterminate progress indicator spinning), this method will throw.
  ///
  /// The default timeout is ten minutes, which is longer than most reasonable
  /// finite animations would last.
  ///
  /// If the function returns, it returns the number of pumps that it performed.
  ///
  /// In general, it is better practice to figure out exactly why each frame is
  /// needed, and then to [pump] exactly as many frames as necessary. This will
  /// help catch regressions where, for instance, an animation is being started
  /// one frame later than it should.
  ///
  /// Alternatively, one can check that the return value from this function
  /// matches the expected number of pumps.
  Future<int> pumpAndSettle([Duration duration = const Duration(milliseconds: 100)]);

  /// Attempts to drag the given widget by the given offset, by
  /// starting a drag in the middle of the widget.
  ///
  /// {@macro flutter.flutter_test.WidgetController.tap.warnIfMissed}
  ///
  /// If you want the drag to end with a speed so that the gesture recognition
  /// system identifies the gesture as a fling, consider using [fling] instead.
  ///
  /// The operation happens at once. If you want the drag to last for a period
  /// of time, consider using [timedDrag].
  ///
  /// {@macro flutter.flutter_test.WidgetController.fling.offset}
  ///
  /// {@template flutter.flutter_test.WidgetController.drag}
  /// By default, if the x or y component of offset is greater than
  /// [kDragSlopDefault], the gesture is broken up into two separate moves
  /// calls. Changing `touchSlopX` or `touchSlopY` will change the minimum
  /// amount of movement in the respective axis before the drag will be broken
  /// into multiple calls. To always send the drag with just a single call to
  /// [TestGesture.moveBy], `touchSlopX` and `touchSlopY` should be set to 0.
  ///
  /// Breaking the drag into multiple moves is necessary for accurate execution
  /// of drag update calls with a [DragStartBehavior] variable set to
  /// [DragStartBehavior.start]. Without such a change, the dragUpdate callback
  /// from a drag recognizer will never be invoked.
  ///
  /// To force this function to a send a single move event, the `touchSlopX` and
  /// `touchSlopY` variables should be set to 0. However, generally, these values
  /// should be left to their default values.
  /// {@endtemplate}
  Future<void> drag(
    finders.FinderBase<Element> finder,
    Offset offset, {
    int? pointer,
    int buttons = kPrimaryButton,
    double touchSlopX = kDragSlopDefault,
    double touchSlopY = kDragSlopDefault,
    bool warnIfMissed = true,
    PointerDeviceKind kind = PointerDeviceKind.touch,
  }) {
    final FlutterView? view = _maybeViewOf(finder);
    return dragFrom(
      getCenter(finder, warnIfMissed: warnIfMissed, callee: 'drag'),
      offset,
      pointer: pointer,
      buttons: buttons,
      touchSlopX: touchSlopX,
      touchSlopY: touchSlopY,
      kind: kind,
      view: view,
    );
  }

  /// Attempts a drag gesture consisting of a pointer down, a move by
  /// the given offset, and a pointer up.
  ///
  /// If you want the drag to end with a speed so that the gesture recognition
  /// system identifies the gesture as a fling, consider using [flingFrom]
  /// instead.
  ///
  /// The operation happens at once. If you want the drag to last for a period
  /// of time, consider using [timedDragFrom].
  ///
  /// {@macro flutter.flutter_test.WidgetController.drag}
  Future<void> dragFrom(
    Offset startLocation,
    Offset offset, {
    int? pointer,
    int buttons = kPrimaryButton,
    double touchSlopX = kDragSlopDefault,
    double touchSlopY = kDragSlopDefault,
    PointerDeviceKind kind = PointerDeviceKind.touch,
    FlutterView? view,
  }) {
    assert(kDragSlopDefault > kTouchSlop);
    return TestAsyncUtils.guard<void>(() async {
      final TestGesture gesture = await startGesture(
        startLocation,
        pointer: pointer,
        buttons: buttons,
        kind: kind,
        view: view,
      );

      final double xSign = offset.dx.sign;
      final double ySign = offset.dy.sign;

      final double offsetX = offset.dx;
      final double offsetY = offset.dy;

      final bool separateX = offset.dx.abs() > touchSlopX && touchSlopX > 0;
      final bool separateY = offset.dy.abs() > touchSlopY && touchSlopY > 0;

      if (separateY || separateX) {
        final double offsetSlope = offsetY / offsetX;
        final double inverseOffsetSlope = offsetX / offsetY;
        final double slopSlope = touchSlopY / touchSlopX;
        final double absoluteOffsetSlope = offsetSlope.abs();
        final double signedSlopX = touchSlopX * xSign;
        final double signedSlopY = touchSlopY * ySign;
        if (absoluteOffsetSlope != slopSlope) {
          // The drag goes through one or both of the extents of the edges of the box.
          if (absoluteOffsetSlope < slopSlope) {
            assert(offsetX.abs() > touchSlopX);
            // The drag goes through the vertical edge of the box.
            // It is guaranteed that the |offsetX| > touchSlopX.
            final double diffY = offsetSlope.abs() * touchSlopX * ySign;

            // The vector from the origin to the vertical edge.
            await gesture.moveBy(Offset(signedSlopX, diffY), view: view);
            if (offsetY.abs() <= touchSlopY) {
              // The drag ends on or before getting to the horizontal extension of the horizontal edge.
              await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - diffY), view: view);
            } else {
              final double diffY2 = signedSlopY - diffY;
              final double diffX2 = inverseOffsetSlope * diffY2;

              // The vector from the edge of the box to the horizontal extension of the horizontal edge.
              await gesture.moveBy(Offset(diffX2, diffY2), view: view);
              await gesture.moveBy(
                Offset(offsetX - diffX2 - signedSlopX, offsetY - signedSlopY),
                view: view,
              );
            }
          } else {
            assert(offsetY.abs() > touchSlopY);
            // The drag goes through the horizontal edge of the box.
            // It is guaranteed that the |offsetY| > touchSlopY.
            final double diffX = inverseOffsetSlope.abs() * touchSlopY * xSign;

            // The vector from the origin to the vertical edge.
            await gesture.moveBy(Offset(diffX, signedSlopY), view: view);
            if (offsetX.abs() <= touchSlopX) {
              // The drag ends on or before getting to the vertical extension of the vertical edge.
              await gesture.moveBy(Offset(offsetX - diffX, offsetY - signedSlopY), view: view);
            } else {
              final double diffX2 = signedSlopX - diffX;
              final double diffY2 = offsetSlope * diffX2;

              // The vector from the edge of the box to the vertical extension of the vertical edge.
              await gesture.moveBy(Offset(diffX2, diffY2), view: view);
              await gesture.moveBy(
                Offset(offsetX - signedSlopX, offsetY - diffY2 - signedSlopY),
                view: view,
              );
            }
          }
        } else {
          // The drag goes through the corner of the box.
          await gesture.moveBy(Offset(signedSlopX, signedSlopY), view: view);
          await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - signedSlopY), view: view);
        }
      } else {
        // The drag ends inside the box.
        await gesture.moveBy(offset, view: view);
      }
      await gesture.up(view: view);
    });
  }

  /// Attempts to drag the given widget by the given offset in the `duration`
  /// time, starting in the middle of the widget.
  ///
  /// {@macro flutter.flutter_test.WidgetController.tap.warnIfMissed}
  ///
  /// {@macro flutter.flutter_test.WidgetController.fling.offset}
  ///
  /// This is the timed version of [drag]. This may or may not result in a
  /// [fling] or ballistic animation, depending on the speed from
  /// `offset/duration`.
  ///
  /// {@template flutter.flutter_test.WidgetController.timedDrag}
  /// The move events are sent at a given `frequency` in Hz (or events per
  /// second). It defaults to 60Hz.
  ///
  /// The movement is linear in time.
  ///
  /// See also [LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive] for
  /// more accurate time control.
  /// {@endtemplate}
  Future<void> timedDrag(
    finders.FinderBase<Element> finder,
    Offset offset,
    Duration duration, {
    int? pointer,
    int buttons = kPrimaryButton,
    double frequency = 60.0,
    bool warnIfMissed = true,
    FlutterView? view,
  }) {
    return timedDragFrom(
      getCenter(finder, warnIfMissed: warnIfMissed, callee: 'timedDrag'),
      offset,
      duration,
      pointer: pointer,
      buttons: buttons,
      frequency: frequency,
      view: view,
    );
  }

  /// Attempts a series of [PointerEvent]s to simulate a drag operation in the
  /// `duration` time.
  ///
  /// This is the timed version of [dragFrom]. This may or may not result in a
  /// [flingFrom] or ballistic animation, depending on the speed from
  /// `offset/duration`.
  ///
  /// {@macro flutter.flutter_test.WidgetController.timedDrag}
  Future<void> timedDragFrom(
    Offset startLocation,
    Offset offset,
    Duration duration, {
    int? pointer,
    int buttons = kPrimaryButton,
    double frequency = 60.0,
    FlutterView? view,
  }) {
    assert(frequency > 0);
    final int intervals = duration.inMicroseconds * frequency ~/ 1E6;
    assert(intervals > 1);
    pointer ??= _getNextPointer();
    final timeStamps = <Duration>[
      for (int t = 0; t <= intervals; t += 1) duration * t ~/ intervals,
    ];
    final offsets = <Offset>[
      startLocation,
      for (int t = 0; t <= intervals; t += 1) startLocation + offset * (t / intervals),
    ];
    final records = <PointerEventRecord>[
      PointerEventRecord(Duration.zero, <PointerEvent>[
        PointerAddedEvent(
          position: startLocation,
          viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
        ),
        PointerDownEvent(position: startLocation, pointer: pointer, buttons: buttons),
      ]),
      ...<PointerEventRecord>[
        for (int t = 0; t <= intervals; t += 1)
          PointerEventRecord(timeStamps[t], <PointerEvent>[
            PointerMoveEvent(
              viewId:
                  view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
              timeStamp: timeStamps[t],
              position: offsets[t + 1],
              delta: offsets[t + 1] - offsets[t],
              pointer: pointer,
              buttons: buttons,
            ),
          ]),
      ],
      PointerEventRecord(duration, <PointerEvent>[
        PointerUpEvent(
          viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
          timeStamp: duration,
          position: offsets.last,
          pointer: pointer,
          // The PointerData received from the engine with
          // change = PointerChange.up, which translates to PointerUpEvent,
          // doesn't provide the button field.
          // buttons: buttons,
        ),
      ]),
    ];
    return TestAsyncUtils.guard<void>(() async {
      await handlePointerEventRecord(records);
    });
  }

  /// The next available pointer identifier.
  ///
  /// This is the default pointer identifier that will be used the next time the
  /// [startGesture] method is called without an explicit pointer identifier.
  int get nextPointer => _nextPointer;

  static int _nextPointer = 1;

  static int _getNextPointer() {
    final int result = _nextPointer;
    _nextPointer += 1;
    return result;
  }

  TestGesture _createGesture({
    int? pointer,
    required PointerDeviceKind kind,
    required int buttons,
  }) {
    return TestGesture(
      dispatcher: sendEventToBinding,
      kind: kind,
      pointer: pointer ?? _getNextPointer(),
      buttons: buttons,
    );
  }

  /// Creates gesture and returns the [TestGesture] object which you can use
  /// to continue the gesture using calls on the [TestGesture] object.
  ///
  /// You can use [startGesture] instead if your gesture begins with a down
  /// event.
  Future<TestGesture> createGesture({
    int? pointer,
    PointerDeviceKind kind = PointerDeviceKind.touch,
    int buttons = kPrimaryButton,
  }) async {
    return _createGesture(pointer: pointer, kind: kind, buttons: buttons);
  }

  /// Creates a gesture with an initial appropriate starting gesture at a
  /// particular point, and returns the [TestGesture] object which you can use
  /// to continue the gesture. Usually, the starting gesture will be a down event,
  /// but if [kind] is set to [PointerDeviceKind.trackpad], the gesture will start
  /// with a panZoomStart gesture.
  ///
  /// You can use [createGesture] if your gesture doesn't begin with an initial
  /// down or panZoomStart gesture.
  ///
  /// See also:
  ///  * [WidgetController.drag], a method to simulate a drag.
  ///  * [WidgetController.timedDrag], a method to simulate the drag of a given
  ///    widget in a given duration. It sends move events at a given frequency and
  ///    it is useful when there are listeners involved.
  ///  * [WidgetController.fling], a method to simulate a fling.
  Future<TestGesture> startGesture(
    Offset downLocation, {
    int? pointer,
    PointerDeviceKind kind = PointerDeviceKind.touch,
    int buttons = kPrimaryButton,
    FlutterView? view,
  }) async {
    final TestGesture result = _createGesture(pointer: pointer, kind: kind, buttons: buttons);
    if (kind == PointerDeviceKind.trackpad) {
      await result.panZoomStart(downLocation, view: view);
    } else {
      await result.down(downLocation, view: view);
    }
    return result;
  }

  /// Forwards the given location to the binding's hitTest logic.
  HitTestResult hitTestOnBinding(Offset location, {int? viewId}) {
    viewId ??= view.viewId;
    final result = HitTestResult();
    binding.hitTestInView(result, location, viewId);
    return result;
  }

  /// Forwards the given pointer event to the binding.
  Future<void> sendEventToBinding(PointerEvent event) {
    return TestAsyncUtils.guard<void>(() async {
      binding.handlePointerEvent(event);
    });
  }

  /// Calls [debugPrint] with the given message.
  ///
  /// This is overridden by the WidgetTester subclass to use the test binding's
  /// [TestWidgetsFlutterBinding.debugPrintOverride], so that it appears on the
  /// console even if the test is logging output from the application.
  @protected
  void printToConsole(String message) {
    debugPrint(message);
  }

  // GEOMETRY

  /// Returns the point at the center of the given widget.
  ///
  /// {@template flutter.flutter_test.WidgetController.getCenter.warnIfMissed}
  /// If `warnIfMissed` is true (the default is false), then the returned
  /// coordinate is checked to see if a hit test at the returned location would
  /// actually include the specified element in the [HitTestResult], and if not,
  /// a warning is printed to the console.
  ///
  /// The `callee` argument is used to identify the method that should be
  /// referenced in messages regarding `warnIfMissed`. It can be ignored unless
  /// this method is being called from another that is forwarding its own
  /// `warnIfMissed` parameter (see e.g. the implementation of [tap]).
  /// {@endtemplate}
  Offset getCenter(
    finders.FinderBase<Element> finder, {
    bool warnIfMissed = false,
    String callee = 'getCenter',
  }) {
    return _getElementPoint(
      finder,
      (Size size) => size.center(Offset.zero),
      warnIfMissed: warnIfMissed,
      callee: callee,
    );
  }

  /// Returns the point at the top left of the given widget.
  ///
  /// {@macro flutter.flutter_test.WidgetController.getCenter.warnIfMissed}
  Offset getTopLeft(
    finders.FinderBase<Element> finder, {
    bool warnIfMissed = false,
    String callee = 'getTopLeft',
  }) {
    return _getElementPoint(
      finder,
      (Size size) => Offset.zero,
      warnIfMissed: warnIfMissed,
      callee: callee,
    );
  }

  /// Returns the point at the top right of the given widget. This
  /// point is not inside the object's hit test area.
  ///
  /// {@macro flutter.flutter_test.WidgetController.getCenter.warnIfMissed}
  Offset getTopRight(
    finders.FinderBase<Element> finder, {
    bool warnIfMissed = false,
    String callee = 'getTopRight',
  }) {
    return _getElementPoint(
      finder,
      (Size size) => size.topRight(Offset.zero),
      warnIfMissed: warnIfMissed,
      callee: callee,
    );
  }

  /// Returns the point at the bottom left of the given widget. This
  /// point is not inside the object's hit test area.
  ///
  /// {@macro flutter.flutter_test.WidgetController.getCenter.warnIfMissed}
  Offset getBottomLeft(
    finders.FinderBase<Element> finder, {
    bool warnIfMissed = false,
    String callee = 'getBottomLeft',
  }) {
    return _getElementPoint(
      finder,
      (Size size) => size.bottomLeft(Offset.zero),
      warnIfMissed: warnIfMissed,
      callee: callee,
    );
  }

  /// Returns the point at the bottom right of the given widget. This
  /// point is not inside the object's hit test area.
  ///
  /// {@macro flutter.flutter_test.WidgetController.getCenter.warnIfMissed}
  Offset getBottomRight(
    finders.FinderBase<Element> finder, {
    bool warnIfMissed = false,
    String callee = 'getBottomRight',
  }) {
    return _getElementPoint(
      finder,
      (Size size) => size.bottomRight(Offset.zero),
      warnIfMissed: warnIfMissed,
      callee: callee,
    );
  }

  /// Whether warnings relating to hit tests not hitting their mark should be
  /// fatal (cause the test to fail).
  ///
  /// Some methods, e.g. [tap], have an argument `warnIfMissed` which causes a
  /// warning to be displayed if the specified [Finder] indicates a widget and
  /// location that, were a pointer event to be sent to that location, would not
  /// actually send any events to the widget (e.g. because the widget is
  /// obscured, or the location is off-screen, or the widget is transparent to
  /// pointer events).
  ///
  /// This warning was added in 2021. In ordinary operation this warning is
  /// non-fatal since making it fatal would be a significantly breaking change
  /// for anyone who already has tests relying on the ability to target events
  /// using finders where the events wouldn't reach the widgets specified by the
  /// finders in question.
  ///
  /// However, doing this is usually unintentional. To make the warning fatal,
  /// thus failing any tests where it occurs, this property can be set to true.
  ///
  /// Typically this is done using a `flutter_test_config.dart` file, as described
  /// in the documentation for the [flutter_test] library.
  static bool hitTestWarningShouldBeFatal = false;

  /// Finds one hit-testable Offset in the given `textRangeContext`'s render
  /// object.
  Offset? _findHitTestableOffsetIn(finders.TextRangeContext textRangeContext) {
    TestAsyncUtils.guardSync();
    final TextRange range = textRangeContext.textRange;
    assert(range.isNormalized);
    assert(range.isValid);
    final Offset renderParagraphPaintOffset = textRangeContext.renderObject.localToGlobal(
      Offset.zero,
    );
    assert(renderParagraphPaintOffset.isFinite);

    int spanStart = range.start;
    while (spanStart < range.end) {
      switch (_findEndOfSpan(textRangeContext.renderObject.text, spanStart, range.end)) {
        case (final HitTestTarget target, final int endIndex):
          // Uses BoxHeightStyle.tight in getBoxesForSelection to make sure the
          // returned boxes don't extend outside of the hit-testable region.
          final Iterable<Offset> testOffsets = textRangeContext.renderObject
              .getBoxesForSelection(TextSelection(baseOffset: spanStart, extentOffset: endIndex))
              // Try hit-testing the center of each TextBox.
              .map((TextBox textBox) => textBox.toRect().center);

          for (final localOffset in testOffsets) {
            final result = HitTestResult();
            final Offset globalOffset = localOffset + renderParagraphPaintOffset;
            binding.hitTestInView(result, globalOffset, textRangeContext.view.view.viewId);
            if (result.path.any((HitTestEntry entry) => entry.target == target)) {
              return globalOffset;
            }
          }
          spanStart = endIndex;
        case (_, final int endIndex):
          spanStart = endIndex;
        case null:
          break;
      }
    }
    return null;
  }

  Offset _getElementPoint(
    finders.FinderBase<Element> finder,
    Offset Function(Size size) sizeToPoint, {
    required bool warnIfMissed,
    required String callee,
  }) {
    TestAsyncUtils.guardSync();
    final Iterable<Element> elements = finder.evaluate();
    if (elements.isEmpty) {
      throw FlutterError(
        'The finder "$finder" (used in a call to "$callee()") could not find any matching widgets.',
      );
    }
    if (elements.length > 1) {
      throw FlutterError(
        'The finder "$finder" (used in a call to "$callee()") ambiguously found multiple matching widgets. The "$callee()" method needs a single target.',
      );
    }
    final Element element = elements.single;
    final RenderObject? renderObject = element.renderObject;
    if (renderObject == null) {
      throw FlutterError(
        'The finder "$finder" (used in a call to "$callee()") found an element, but it does not have a corresponding render object. '
        'Maybe the element has not yet been rendered?',
      );
    }
    if (renderObject is! RenderBox) {
      throw FlutterError(
        'The finder "$finder" (used in a call to "$callee()") found an element whose corresponding render object is not a RenderBox (it is a ${renderObject.runtimeType}: "$renderObject"). '
        'Unfortunately "$callee()" only supports targeting widgets that correspond to RenderBox objects in the rendering.',
      );
    }
    final box = element.renderObject! as RenderBox;
    final Offset location = box.localToGlobal(sizeToPoint(box.size));
    if (warnIfMissed) {
      final FlutterView view = _viewOf(finder);
      final result = HitTestResult();
      binding.hitTestInView(result, location, view.viewId);
      final bool found = result.path.any((HitTestEntry entry) => entry.target == box);
      if (!found) {
        final RenderView renderView = binding.renderViews.firstWhere(
          (RenderView r) => r.flutterView == view,
        );
        final bool outOfBounds = !(Offset.zero & renderView.size).contains(location);
        if (hitTestWarningShouldBeFatal) {
          throw FlutterError.fromParts(<DiagnosticsNode>[
            ErrorSummary('Finder specifies a widget that would not receive pointer events.'),
            ErrorDescription(
              'A call to $callee() with finder "$finder" derived an Offset ($location) that would not hit test on the specified widget.',
            ),
            ErrorHint(
              'Maybe the widget is actually off-screen, or another widget is obscuring it, or the widget cannot receive pointer events.',
            ),
            if (outOfBounds)
              ErrorHint(
                'Indeed, $location is outside the bounds of the root of the render tree, ${renderView.size}.',
              ),
            box.toDiagnosticsNode(
              name: 'The finder corresponds to this RenderBox',
              style: DiagnosticsTreeStyle.singleLine,
            ),
            ErrorDescription('The hit test result at that offset is: $result'),
            ErrorDescription(
              'If you expected this target not to be able to receive pointer events, pass "warnIfMissed: false" to "$callee()".',
            ),
            ErrorDescription(
              'To make this error into a non-fatal warning, set WidgetController.hitTestWarningShouldBeFatal to false.',
            ),
          ]);
        }
        printToConsole(
          '\n'
          'Warning: A call to $callee() with finder "$finder" derived an Offset ($location) that would not hit test on the specified widget.\n'
          'Maybe the widget is actually off-screen, or another widget is obscuring it, or the widget cannot receive pointer events.\n'
          '${outOfBounds ? "Indeed, $location is outside the bounds of the root of the render tree, ${renderView.size}.\n" : ""}'
          'The finder corresponds to this RenderBox: $box\n'
          'The hit test result at that offset is: $result\n'
          '${StackTrace.current}'
          'To silence this warning, pass "warnIfMissed: false" to "$callee()".\n'
          'To make this warning fatal, set WidgetController.hitTestWarningShouldBeFatal to true.\n',
        );
      }
    }
    return location;
  }

  /// Returns the size of the given widget. This is only valid once
  /// the widget's render object has been laid out at least once.
  Size getSize(finders.FinderBase<Element> finder) {
    TestAsyncUtils.guardSync();
    final Element element = finder.evaluate().single;
    final box = element.renderObject! as RenderBox;
    return box.size;
  }

  /// Simulates sending physical key down and up events.
  ///
  /// This only simulates key events coming from a physical keyboard, not from a
  /// soft keyboard.
  ///
  /// Specify `platform` as one of the platforms allowed in
  /// [Platform.operatingSystem] to make the event appear to be from
  /// that type of system. If not specified, defaults to "web" on web, and the
  /// operating system name based on [defaultTargetPlatform] everywhere else.
  ///
  /// Specify the `physicalKey` for the event to override what is included in
  /// the simulated event. If not specified, it uses a default from the US
  /// keyboard layout for the corresponding logical `key`.
  ///
  /// Specify the `character` for the event to override what is included in the
  /// simulated event. If not specified, it uses a default derived from the
  /// logical `key`.
  ///
  /// Keys that are down when the test completes are cleared after each test.
  ///
  /// This method sends both the key down and the key up events, to simulate a
  /// key press. To simulate individual down and/or up events, see
  /// [sendKeyDownEvent] and [sendKeyUpEvent].
  ///
  /// Returns true if the key down event was handled by the framework.
  ///
  /// See also:
  ///
  ///  - [sendKeyDownEvent] to simulate only a key down event.
  ///  - [sendKeyUpEvent] to simulate only a key up event.
  Future<bool> sendKeyEvent(
    LogicalKeyboardKey key, {
    String? platform,
    String? character,
    PhysicalKeyboardKey? physicalKey,
  }) async {
    final bool handled = await simulateKeyDownEvent(
      key,
      platform: platform,
      character: character,
      physicalKey: physicalKey,
    );
    // Internally wrapped in async guard.
    await simulateKeyUpEvent(key, platform: platform, physicalKey: physicalKey);
    return handled;
  }

  /// Simulates sending a physical key down event.
  ///
  /// This only simulates key down events coming from a physical keyboard, not
  /// from a soft keyboard.
  ///
  /// Specify `platform` as one of the platforms allowed in
  /// [Platform.operatingSystem] to make the event appear to be from
  /// that type of system. If not specified, defaults to "web" on web, and the
  /// operating system name based on [defaultTargetPlatform] everywhere else.
  ///
  /// Specify the `physicalKey` for the event to override what is included in
  /// the simulated event. If not specified, it uses a default from the US
  /// keyboard layout for the corresponding logical `key`.
  ///
  /// Specify the `character` for the event to override what is included in the
  /// simulated event. If not specified, it uses a default derived from the
  /// logical `key`.
  ///
  /// Keys that are down when the test completes are cleared after each test.
  ///
  /// Returns true if the key event was handled by the framework.
  ///
  /// See also:
  ///
  ///  - [sendKeyUpEvent] and [sendKeyRepeatEvent] to simulate the corresponding
  ///    key up and repeat event.
  ///  - [sendKeyEvent] to simulate both the key up and key down in the same call.
  Future<bool> sendKeyDownEvent(
    LogicalKeyboardKey key, {
    String? platform,
    String? character,
    PhysicalKeyboardKey? physicalKey,
  }) async {
    // Internally wrapped in async guard.
    return simulateKeyDownEvent(
      key,
      platform: platform,
      character: character,
      physicalKey: physicalKey,
    );
  }

  /// Simulates sending a physical key up event through the system channel.
  ///
  /// This only simulates key up events coming from a physical keyboard,
  /// not from a soft keyboard.
  ///
  /// Specify `platform` as one of the platforms allowed in
  /// [Platform.operatingSystem] to make the event appear to be from
  /// that type of system. If not specified, defaults to "web" on web, and the
  /// operating system name based on [defaultTargetPlatform] everywhere else.
  ///
  /// Specify the `physicalKey` for the event to override what is included in
  /// the simulated event. If not specified, it uses a default from the US
  /// keyboard layout for the corresponding logical `key`.
  ///
  /// Returns true if the key event was handled by the framework.
  ///
  /// See also:
  ///
  ///  - [sendKeyDownEvent] and [sendKeyRepeatEvent] to simulate the
  ///    corresponding key down and repeat event.
  ///  - [sendKeyEvent] to simulate both the key up and key down in the same call.
  Future<bool> sendKeyUpEvent(
    LogicalKeyboardKey key, {
    String? platform,
    PhysicalKeyboardKey? physicalKey,
  }) async {
    // Internally wrapped in async guard.
    return simulateKeyUpEvent(key, platform: platform, physicalKey: physicalKey);
  }

  /// Simulates sending a key repeat event from a physical keyboard.
  ///
  /// This only simulates key repeat events coming from a physical keyboard, not
  /// from a soft keyboard.
  ///
  /// Specify `platform` as one of the platforms allowed in
  /// [Platform.operatingSystem] to make the event appear to be from
  /// that type of system. If not specified, defaults to "web" on web, and the
  /// operating system name based on [defaultTargetPlatform] everywhere else.
  ///
  /// Specify the `physicalKey` for the event to override what is included in
  /// the simulated event. If not specified, it uses a default from the US
  /// keyboard layout for the corresponding logical `key`.
  ///
  /// Specify the `character` for the event to override what is included in the
  /// simulated event. If not specified, it uses a default derived from the
  /// logical `key`.
  ///
  /// Keys that are down when the test completes are cleared after each test.
  ///
  /// Returns true if the key event was handled by the framework.
  ///
  /// See also:
  ///
  ///  - [sendKeyDownEvent] and [sendKeyUpEvent] to simulate the corresponding
  ///    key down and up event.
  ///  - [sendKeyEvent] to simulate both the key up and key down in the same call.
  Future<bool> sendKeyRepeatEvent(
    LogicalKeyboardKey key, {
    String? platform,
    String? character,
    PhysicalKeyboardKey? physicalKey,
  }) async {
    // Internally wrapped in async guard.
    return simulateKeyRepeatEvent(
      key,
      platform: platform,
      character: character,
      physicalKey: physicalKey,
    );
  }

  /// Returns the rect of the given widget. This is only valid once
  /// the widget's render object has been laid out at least once.
  Rect getRect(finders.FinderBase<Element> finder) =>
      Rect.fromPoints(getTopLeft(finder), getBottomRight(finder));

  /// Attempts to find the [SemanticsNode] of first result from `finder`.
  ///
  /// If the object identified by the finder doesn't own it's semantic node,
  /// this will return the semantics data of the first ancestor with semantics.
  /// The ancestor's semantic data will include the child's as well as
  /// other nodes that have been merged together.
  ///
  /// If the [SemanticsNode] of the object identified by the finder is
  /// force-merged into an ancestor (e.g. via the [MergeSemantics] widget)
  /// the node into which it is merged is returned. That node will include
  /// all the semantics information of the nodes merged into it.
  ///
  /// Will throw a [StateError] if the finder returns more than one element or
  /// if no semantics are found or are not enabled.
  // TODO(pdblasi-google): Deprecate this and point references to semantics.find. See https://github.com/flutter/flutter/issues/112670.
  SemanticsNode getSemantics(finders.FinderBase<Element> finder) => semantics.find(finder);

  /// Enable semantics in a test by creating a [SemanticsHandle].
  ///
  /// The handle must be disposed at the end of the test.
  SemanticsHandle ensureSemantics() {
    return binding.ensureSemantics();
  }

  /// Given a widget `W` specified by [finder] and a [Scrollable] widget `S` in
  /// its ancestry tree, this scrolls `S` so as to make `W` visible.
  ///
  /// Usually the `finder` for this method should be labeled `skipOffstage:
  /// false`, so that the [Finder] deals with widgets that are off the screen
  /// correctly.
  ///
  /// This does not work when `S` is long enough, and `W` far away enough from
  /// the displayed part of `S`, that `S` has not yet cached `W`'s element.
  /// Consider using [scrollUntilVisible] in such a situation.
  ///
  /// See also:
  ///
  ///  * [Scrollable.ensureVisible], which is the production API used to
  ///    implement this method.
  Future<void> ensureVisible(finders.FinderBase<Element> finder) =>
      Scrollable.ensureVisible(element(finder));

  /// Repeatedly scrolls a [Scrollable] by `delta` in the
  /// [Scrollable.axisDirection] direction until a widget matching `finder` is
  /// visible.
  ///
  /// Between each scroll, advances the clock by `duration` time.
  ///
  /// Scrolling is performed until the start of the `finder` is visible. This is
  /// due to the default parameter values of the [Scrollable.ensureVisible] method.
  ///
  /// If `scrollable` is `null`, a [Finder] that looks for a [Scrollable] is
  /// used instead.
  ///
  /// If `continuous` is `true`, the gesture will be reused to simulate the effect
  /// of actual finger scrolling, which is useful when used alongside listeners
  /// like [GestureDetector.onTap]. The default is `false`.
  ///
  /// Throws a [StateError] if `finder` is not found after `maxScrolls` scrolls.
  ///
  /// This is different from [ensureVisible] in that this allows looking for
  /// `finder` that is not yet built. The caller must specify the scrollable
  /// that will build child specified by `finder` when there are multiple
  /// [Scrollable]s.
  ///
  /// See also:
  ///
  ///  * [dragUntilVisible], which implements the body of this method.
  Future<void> scrollUntilVisible(
    finders.FinderBase<Element> finder,
    double delta, {
    finders.FinderBase<Element>? scrollable,
    int maxScrolls = 50,
    Duration duration = const Duration(milliseconds: 50),
    bool continuous = false,
  }) {
    assert(maxScrolls > 0);
    scrollable ??= finders.find.byType(Scrollable);
    return TestAsyncUtils.guard<void>(() async {
      Offset moveStep;
      switch (widget<Scrollable>(scrollable!).axisDirection) {
        case AxisDirection.up:
          moveStep = Offset(0, delta);
        case AxisDirection.down:
          moveStep = Offset(0, -delta);
        case AxisDirection.left:
          moveStep = Offset(delta, 0);
        case AxisDirection.right:
          moveStep = Offset(-delta, 0);
      }
      await dragUntilVisible(
        finder,
        scrollable,
        moveStep,
        maxIteration: maxScrolls,
        duration: duration,
        continuous: continuous,
      );
    });
  }

  /// Repeatedly drags `view` by `moveStep` until `finder` is visible.
  ///
  /// Between each drag, advances the clock by `duration`.
  ///
  /// Throws a [StateError] if `finder` is not found after `maxIteration`
  /// drags.
  ///
  /// See also:
  ///
  ///  * [scrollUntilVisible], which wraps this method with an API that is more
  ///    convenient when dealing with a [Scrollable].
  Future<void> dragUntilVisible(
    finders.FinderBase<Element> finder,
    finders.FinderBase<Element> view,
    Offset moveStep, {
    int maxIteration = 50,
    Duration duration = const Duration(milliseconds: 50),
    bool continuous = false,
  }) {
    return TestAsyncUtils.guard<void>(() async {
      TestGesture? gesture;
      while (maxIteration > 0 && finder.evaluate().isEmpty) {
        if (continuous) {
          gesture ??= await startGesture(getCenter(view, warnIfMissed: true));
          await gesture.moveBy(moveStep);
        } else {
          await drag(view, moveStep);
        }
        await pump(duration);
        maxIteration -= 1;
      }
      await gesture?.up();
      await Scrollable.ensureVisible(element(finder));
    });
  }
}

/// Variant of [WidgetController] that can be used in tests running
/// on a device.
///
/// This is used, for instance, by [FlutterDriver].
class LiveWidgetController extends WidgetController {
  /// Creates a widget controller that uses the given binding.
  LiveWidgetController(super.binding);

  @override
  Future<void> pump([Duration? duration]) async {
    if (duration != null) {
      await Future<void>.delayed(duration);
    }
    binding.scheduleFrame();
    await binding.endOfFrame;
  }

  @override
  Future<int> pumpAndSettle([Duration duration = const Duration(milliseconds: 100)]) {
    assert(duration > Duration.zero);
    return TestAsyncUtils.guard<int>(() async {
      var count = 0;
      do {
        await pump(duration);
        count += 1;
      } while (binding.hasScheduledFrame);
      return count;
    });
  }

  @override
  Future<List<Duration>> handlePointerEventRecord(List<PointerEventRecord> records) {
    assert(records.isNotEmpty);
    return TestAsyncUtils.guard<List<Duration>>(() async {
      final handleTimeStampDiff = <Duration>[];
      DateTime? startTime;
      for (final record in records) {
        final DateTime now = clock.now();
        startTime ??= now;
        // So that the first event is promised to receive a zero timeDiff.
        final Duration timeDiff = record.timeDelay - now.difference(startTime);
        if (timeDiff.isNegative) {
          // This happens when something (e.g. GC) takes a long time during the
          // processing of the events.
          // Flush all past events.
          handleTimeStampDiff.add(-timeDiff);
          record.events.forEach(binding.handlePointerEvent);
        } else {
          await Future<void>.delayed(timeDiff);
          handleTimeStampDiff.add(
            // Recalculating the time diff for getting exact time when the event
            // packet is sent. For a perfect Future.delayed like the one in a
            // fake async this new diff should be zero.
            clock.now().difference(startTime) - record.timeDelay,
          );
          record.events.forEach(binding.handlePointerEvent);
        }
      }

      return handleTimeStampDiff;
    });
  }
}
