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

import 'dart:ui' as ui;
import 'dart:ui' show PointerChange;

import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';

import 'mouse_tracker_test_utils.dart';

MouseTracker get _mouseTracker => RendererBinding.instance.mouseTracker;

typedef SimpleAnnotationFinder = Iterable<TestAnnotationEntry> Function(Offset offset);

void main() {
  final TestMouseTrackerFlutterBinding binding = TestMouseTrackerFlutterBinding();
  void setUpMouseAnnotationFinder(SimpleAnnotationFinder annotationFinder) {
    binding.setHitTest((BoxHitTestResult result, Offset position) {
      for (final TestAnnotationEntry entry in annotationFinder(position)) {
        result.addWithRawTransform(
          transform: entry.transform,
          position: position,
          hitTest: (BoxHitTestResult result, Offset position) {
            result.add(entry);
            return true;
          },
        );
      }
      return true;
    });
  }

  // Set up a trivial test environment that includes one annotation.
  // This annotation records the enter, hover, and exit events it receives to
  // `logEvents`.
  // This annotation also contains a cursor with a value of `testCursor`.
  // The mouse tracker records the cursor requests it receives to `logCursors`.
  TestAnnotationTarget setUpWithOneAnnotation({
    required List<PointerEvent> logEvents,
  }) {
    final TestAnnotationTarget oneAnnotation = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) {
        if (logEvents != null) {
          logEvents.add(event);
        }
      },
      onHover: (PointerHoverEvent event) {
        if (logEvents != null) {
          logEvents.add(event);
        }
      },
      onExit: (PointerExitEvent event) {
        if (logEvents != null) {
          logEvents.add(event);
        }
      },
    );
    setUpMouseAnnotationFinder(
      (Offset position) sync* {
        yield TestAnnotationEntry(oneAnnotation);
      },
    );
    return oneAnnotation;
  }

  void dispatchRemoveDevice([int device = 0]) {
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, Offset.zero, device: device),
    ]));
  }

  setUp(() {
    binding.postFrameCallbacks.clear();
  });

  final Matrix4 translate10by20 = Matrix4.translationValues(10, 20, 0);

  test('should detect enter, hover, and exit from Added, Hover, and Removed events', () {
    final List<PointerEvent> events = <PointerEvent>[];
    setUpWithOneAnnotation(logEvents: events);

    final List<bool> listenerLogs = <bool>[];
    _mouseTracker.addListener(() {
      listenerLogs.add(_mouseTracker.mouseIsConnected);
    });

    expect(_mouseTracker.mouseIsConnected, isFalse);

    // Pointer enters the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));
    addTearDown(() => dispatchRemoveDevice());

    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerEnterEvent>(const PointerEnterEvent()),
    ]));
    expect(listenerLogs, <bool>[true]);
    events.clear();
    listenerLogs.clear();

    // Pointer hovers the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(1.0, 101.0)),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerHoverEvent>(const PointerHoverEvent(position: Offset(1.0, 101.0))),
    ]));
    expect(_mouseTracker.mouseIsConnected, isTrue);
    expect(listenerLogs, isEmpty);
    events.clear();

    // Pointer is removed while on the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, const Offset(1.0, 101.0)),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerExitEvent>(const PointerExitEvent(position: Offset(1.0, 101.0))),
    ]));
    expect(listenerLogs, <bool>[false]);
    events.clear();
    listenerLogs.clear();

    // Pointer is added on the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 301.0)),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerEnterEvent>(const PointerEnterEvent(position: Offset(0.0, 301.0))),
    ]));
    expect(listenerLogs, <bool>[true]);
    events.clear();
    listenerLogs.clear();
  });

  // Regression test for https://github.com/flutter/flutter/issues/90838
  test('should not crash if the first event is a Removed event', () {
    final List<PointerEvent> events = <PointerEvent>[];
    setUpWithOneAnnotation(logEvents: events);
    ui.window.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, Offset.zero),
    ]));
    events.clear();
  });

  test('should correctly handle multiple devices', () {
    final List<PointerEvent> events = <PointerEvent>[];
    setUpWithOneAnnotation(logEvents: events);

    expect(_mouseTracker.mouseIsConnected, isFalse);

    // The first mouse is added on the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
      _pointerData(PointerChange.hover, const Offset(0.0, 1.0)),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerEnterEvent>(const PointerEnterEvent()),
      EventMatcher<PointerHoverEvent>(const PointerHoverEvent(position: Offset(0.0, 1.0))),
    ]));
    expect(_mouseTracker.mouseIsConnected, isTrue);
    events.clear();

    // The second mouse is added on the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 401.0), device: 1),
      _pointerData(PointerChange.hover, const Offset(1.0, 401.0), device: 1),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerEnterEvent>(const PointerEnterEvent(position: Offset(0.0, 401.0), device: 1)),
      EventMatcher<PointerHoverEvent>(const PointerHoverEvent(position: Offset(1.0, 401.0), device: 1)),
    ]));
    expect(_mouseTracker.mouseIsConnected, isTrue);
    events.clear();

    // The first mouse moves on the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(0.0, 101.0)),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerHoverEvent>(const PointerHoverEvent(position: Offset(0.0, 101.0))),
    ]));
    expect(_mouseTracker.mouseIsConnected, isTrue);
    events.clear();

    // The second mouse moves on the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(1.0, 501.0), device: 1),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerHoverEvent>(const PointerHoverEvent(position: Offset(1.0, 501.0), device: 1)),
    ]));
    expect(_mouseTracker.mouseIsConnected, isTrue);
    events.clear();

    // The first mouse is removed while on the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, const Offset(0.0, 101.0)),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerExitEvent>(const PointerExitEvent(position: Offset(0.0, 101.0))),
    ]));
    expect(_mouseTracker.mouseIsConnected, isTrue);
    events.clear();

    // The second mouse still moves on the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(1.0, 601.0), device: 1),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerHoverEvent>(const PointerHoverEvent(position: Offset(1.0, 601.0), device: 1)),
    ]));
    expect(_mouseTracker.mouseIsConnected, isTrue);
    events.clear();

    // The second mouse is removed while on the annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, const Offset(1.0, 601.0), device: 1),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerExitEvent>(const PointerExitEvent(position: Offset(1.0, 601.0), device: 1)),
    ]));
    expect(_mouseTracker.mouseIsConnected, isFalse);
    events.clear();
  });

  test('should not handle non-hover events', () {
    final List<PointerEvent> events = <PointerEvent>[];
    setUpWithOneAnnotation(logEvents: events);

    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 101.0)),
      _pointerData(PointerChange.down, const Offset(0.0, 101.0)),
    ]));
    addTearDown(() => dispatchRemoveDevice());
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      // This Enter event is triggered by the [PointerAddedEvent] The
      // [PointerDownEvent] is ignored by [MouseTracker].
      EventMatcher<PointerEnterEvent>(const PointerEnterEvent(position: Offset(0.0, 101.0))),
    ]));
    events.clear();

    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.move, const Offset(0.0, 201.0)),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[]));
    events.clear();

    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.up, const Offset(0.0, 301.0)),
    ]));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[]));
    events.clear();
  });

  test('should correctly handle when the annotation appears or disappears on the pointer', () {
    late bool isInHitRegion;
    final List<Object> events = <PointerEvent>[];
    final TestAnnotationTarget annotation = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) => events.add(event),
      onHover: (PointerHoverEvent event) => events.add(event),
      onExit: (PointerExitEvent event) => events.add(event),
    );
    setUpMouseAnnotationFinder((Offset position) sync* {
      if (isInHitRegion) {
        yield TestAnnotationEntry(annotation, Matrix4.translationValues(10, 20, 0));
      }
    });

    isInHitRegion = false;

    // Connect a mouse when there is no annotation.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 100.0)),
    ]));
    addTearDown(() => dispatchRemoveDevice());
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[]));
    expect(_mouseTracker.mouseIsConnected, isTrue);
    events.clear();

    // Adding an annotation should trigger Enter event.
    isInHitRegion = true;
    binding.scheduleMouseTrackerPostFrameCheck();
    expect(binding.postFrameCallbacks, hasLength(1));

    binding.flushPostFrameCallbacks(Duration.zero);
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerEnterEvent>(const PointerEnterEvent(position: Offset(0, 100)).transformed(translate10by20)),
    ]));
    events.clear();

    // Removing an annotation should trigger events.
    isInHitRegion = false;
    binding.scheduleMouseTrackerPostFrameCheck();
    expect(binding.postFrameCallbacks, hasLength(1));

    binding.flushPostFrameCallbacks(Duration.zero);
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerExitEvent>(const PointerExitEvent(position: Offset(0.0, 100.0)).transformed(translate10by20)),
    ]));
    expect(binding.postFrameCallbacks, hasLength(0));
  });

  test('should correctly handle when the annotation moves in or out of the pointer', () {
    late bool isInHitRegion;
    final List<Object> events = <PointerEvent>[];
    final TestAnnotationTarget annotation = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) => events.add(event),
      onHover: (PointerHoverEvent event) => events.add(event),
      onExit: (PointerExitEvent event) => events.add(event),
    );
    setUpMouseAnnotationFinder((Offset position) sync* {
      if (isInHitRegion) {
        yield TestAnnotationEntry(annotation, Matrix4.translationValues(10, 20, 0));
      }
    });

    isInHitRegion = false;

    // Connect a mouse.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 100.0)),
    ]));
    addTearDown(() => dispatchRemoveDevice());
    events.clear();

    // During a frame, the annotation moves into the pointer.
    isInHitRegion = true;
    expect(binding.postFrameCallbacks, hasLength(0));
    binding.scheduleMouseTrackerPostFrameCheck();
    expect(binding.postFrameCallbacks, hasLength(1));

    binding.flushPostFrameCallbacks(Duration.zero);
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerEnterEvent>(const PointerEnterEvent(position: Offset(0.0, 100.0)).transformed(translate10by20)),
    ]));
    events.clear();

    expect(binding.postFrameCallbacks, hasLength(0));

    // During a frame, the annotation moves out of the pointer.
    isInHitRegion = false;
    expect(binding.postFrameCallbacks, hasLength(0));
    binding.scheduleMouseTrackerPostFrameCheck();
    expect(binding.postFrameCallbacks, hasLength(1));

    binding.flushPostFrameCallbacks(Duration.zero);
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerExitEvent>(const PointerExitEvent(position: Offset(0.0, 100.0)).transformed(translate10by20)),
    ]));
    expect(binding.postFrameCallbacks, hasLength(0));
  });

  test('should correctly handle when the pointer is added or removed on the annotation', () {
    late bool isInHitRegion;
    final List<Object> events = <PointerEvent>[];
    final TestAnnotationTarget annotation = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) => events.add(event),
      onHover: (PointerHoverEvent event) => events.add(event),
      onExit: (PointerExitEvent event) => events.add(event),
    );
    setUpMouseAnnotationFinder((Offset position) sync* {
      if (isInHitRegion) {
        yield TestAnnotationEntry(annotation, Matrix4.translationValues(10, 20, 0));
      }
    });

    isInHitRegion = false;

    // Connect a mouse in the region. Should trigger Enter.
    isInHitRegion = true;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 100.0)),
    ]));

    expect(binding.postFrameCallbacks, hasLength(0));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerEnterEvent>(const PointerEnterEvent(position: Offset(0.0, 100.0)).transformed(translate10by20)),
    ]));
    events.clear();

    // Disconnect the mouse from the region. Should trigger Exit.
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.remove, const Offset(0.0, 100.0)),
    ]));
    expect(binding.postFrameCallbacks, hasLength(0));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerExitEvent>(const PointerExitEvent(position: Offset(0.0, 100.0)).transformed(translate10by20)),
    ]));
  });

  test('should correctly handle when the pointer moves in or out of the annotation', () {
    late bool isInHitRegion;
    final List<Object> events = <PointerEvent>[];
    final TestAnnotationTarget annotation = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) => events.add(event),
      onHover: (PointerHoverEvent event) => events.add(event),
      onExit: (PointerExitEvent event) => events.add(event),
    );
    setUpMouseAnnotationFinder((Offset position) sync* {
      if (isInHitRegion) {
        yield TestAnnotationEntry(annotation, Matrix4.translationValues(10, 20, 0));
      }
    });

    isInHitRegion = false;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(200.0, 100.0)),
    ]));
    addTearDown(() => dispatchRemoveDevice());

    expect(binding.postFrameCallbacks, hasLength(0));
    events.clear();

    // Moves the mouse into the region. Should trigger Enter.
    isInHitRegion = true;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(0.0, 100.0)),
    ]));
    expect(binding.postFrameCallbacks, hasLength(0));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerEnterEvent>(const PointerEnterEvent(position: Offset(0.0, 100.0)).transformed(translate10by20)),
      EventMatcher<PointerHoverEvent>(const PointerHoverEvent(position: Offset(0.0, 100.0)).transformed(translate10by20)),
    ]));
    events.clear();

    // Moves the mouse out of the region. Should trigger Exit.
    isInHitRegion = false;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(200.0, 100.0)),
    ]));
    expect(binding.postFrameCallbacks, hasLength(0));
    expect(events, _equalToEventsOnCriticalFields(<BaseEventMatcher>[
      EventMatcher<PointerExitEvent>(const PointerExitEvent(position: Offset(200.0, 100.0)).transformed(translate10by20)),
    ]));
  });

  test('should not schedule post-frame callbacks when no mouse is connected', () {
    setUpMouseAnnotationFinder((Offset position) sync* {
    });

    // Connect a touch device, which should not be recognized by MouseTracker
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 100.0), kind: PointerDeviceKind.touch),
    ]));
    expect(_mouseTracker.mouseIsConnected, isFalse);

    expect(binding.postFrameCallbacks, hasLength(0));
  });

  test('should not flip out if not all mouse events are listened to', () {
    bool isInHitRegionOne = true;
    bool isInHitRegionTwo = false;
    final TestAnnotationTarget annotation1 = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) {},
    );
    final TestAnnotationTarget annotation2 = TestAnnotationTarget(
      onExit: (PointerExitEvent event) {},
    );
    setUpMouseAnnotationFinder((Offset position) sync* {
      if (isInHitRegionOne) {
        yield TestAnnotationEntry(annotation1);
      } else if (isInHitRegionTwo) {
        yield TestAnnotationEntry(annotation2);
      }
    });

    isInHitRegionOne = false;
    isInHitRegionTwo = true;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 101.0)),
      _pointerData(PointerChange.hover, const Offset(1.0, 101.0)),
    ]));
    addTearDown(() => dispatchRemoveDevice());

    // Passes if no errors are thrown.
  });

  test('should trigger callbacks between parents and children in correct order', () {
    // This test simulates the scenario of a layer being the child of another.
    //
    //   ———————————
    //   |A        |
    //   |  —————— |
    //   |  |B   | |
    //   |  —————— |
    //   ———————————

    late bool isInB;
    final List<String> logs = <String>[];
    final TestAnnotationTarget annotationA = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) => logs.add('enterA'),
      onExit: (PointerExitEvent event) => logs.add('exitA'),
      onHover: (PointerHoverEvent event) => logs.add('hoverA'),
    );
    final TestAnnotationTarget annotationB = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) => logs.add('enterB'),
      onExit: (PointerExitEvent event) => logs.add('exitB'),
      onHover: (PointerHoverEvent event) => logs.add('hoverB'),
    );
    setUpMouseAnnotationFinder((Offset position) sync* {
      // Children's annotations come before parents'.
      if (isInB) {
        yield TestAnnotationEntry(annotationB);
        yield TestAnnotationEntry(annotationA);
      }
    });

    // Starts out of A.
    isInB = false;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 1.0)),
    ]));
    addTearDown(() => dispatchRemoveDevice());
    expect(logs, <String>[]);

    // Moves into B within one frame.
    isInB = true;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(0.0, 10.0)),
    ]));
    expect(logs, <String>['enterA', 'enterB', 'hoverB', 'hoverA']);
    logs.clear();

    // Moves out of A within one frame.
    isInB = false;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(0.0, 20.0)),
    ]));
    expect(logs, <String>['exitB', 'exitA']);
  });

  test('should trigger callbacks between disjoint siblings in correctly order', () {
    // This test simulates the scenario of 2 sibling layers that do not overlap
    // with each other.
    //
    //   ————————  ————————
    //   |A     |  |B     |
    //   |      |  |      |
    //   ————————  ————————

    late bool isInA;
    late bool isInB;
    final List<String> logs = <String>[];
    final TestAnnotationTarget annotationA = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) => logs.add('enterA'),
      onExit: (PointerExitEvent event) => logs.add('exitA'),
      onHover: (PointerHoverEvent event) => logs.add('hoverA'),
    );
    final TestAnnotationTarget annotationB = TestAnnotationTarget(
      onEnter: (PointerEnterEvent event) => logs.add('enterB'),
      onExit: (PointerExitEvent event) => logs.add('exitB'),
      onHover: (PointerHoverEvent event) => logs.add('hoverB'),
    );
    setUpMouseAnnotationFinder((Offset position) sync* {
      if (isInA) {
        yield TestAnnotationEntry(annotationA);
      } else if (isInB) {
        yield TestAnnotationEntry(annotationB);
      }
    });

    // Starts within A.
    isInA = true;
    isInB = false;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, const Offset(0.0, 1.0)),
    ]));
    addTearDown(() => dispatchRemoveDevice());
    expect(logs, <String>['enterA']);
    logs.clear();

    // Moves into B within one frame.
    isInA = false;
    isInB = true;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(0.0, 10.0)),
    ]));
    expect(logs, <String>['exitA', 'enterB', 'hoverB']);
    logs.clear();

    // Moves into A within one frame.
    isInA = true;
    isInB = false;
    RendererBinding.instance.platformDispatcher.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.hover, const Offset(0.0, 1.0)),
    ]));
    expect(logs, <String>['exitB', 'enterA', 'hoverA']);
  });
}

ui.PointerData _pointerData(
  PointerChange change,
  Offset logicalPosition, {
  int device = 0,
  PointerDeviceKind kind = PointerDeviceKind.mouse,
}) {
  return ui.PointerData(
    change: change,
    physicalX: logicalPosition.dx * RendererBinding.instance.window.devicePixelRatio,
    physicalY: logicalPosition.dy * RendererBinding.instance.window.devicePixelRatio,
    kind: kind,
    device: device,
  );
}

class BaseEventMatcher extends Matcher {
  BaseEventMatcher(this.expected)
    : assert(expected != null);

  final PointerEvent expected;

  bool _matchesField(Map<dynamic, dynamic> matchState, String field, dynamic actual, dynamic expected) {
    if (actual != expected) {
      addStateInfo(matchState, <dynamic, dynamic>{
        'field': field,
        'expected': expected,
        'actual': actual,
      });
      return false;
    }
    return true;
  }

  @override
  bool matches(dynamic untypedItem, Map<dynamic, dynamic> matchState) {
    final PointerEvent actual = untypedItem as PointerEvent;
    if (!(
      _matchesField(matchState, 'kind', actual.kind, PointerDeviceKind.mouse) &&
      _matchesField(matchState, 'position', actual.position, expected.position) &&
      _matchesField(matchState, 'device', actual.device, expected.device) &&
      _matchesField(matchState, 'localPosition', actual.localPosition, expected.localPosition)
    )) {
      return false;
    }
    return true;
  }

  @override
  Description describe(Description description) {
    return description
      .add('event (critical fields only) ')
      .addDescriptionOf(expected);
  }

  @override
  Description describeMismatch(
    dynamic item,
    Description mismatchDescription,
    Map<dynamic, dynamic> matchState,
    bool verbose,
  ) {
    return mismatchDescription
      .add('has ')
      .addDescriptionOf(matchState['actual'])
      .add(" at field `${matchState['field']}`, which doesn't match the expected ")
      .addDescriptionOf(matchState['expected']);
  }
}

class EventMatcher<T extends PointerEvent> extends BaseEventMatcher {
  EventMatcher(T super.expected);

  @override
  bool matches(dynamic untypedItem, Map<dynamic, dynamic> matchState) {
    if (untypedItem is! T) {
      return false;
    }

    return super.matches(untypedItem, matchState);
  }

  @override
  Description describeMismatch(
    dynamic item,
    Description mismatchDescription,
    Map<dynamic, dynamic> matchState,
    bool verbose,
  ) {
    if (item is! T) {
      return mismatchDescription
        .add('is ')
        .addDescriptionOf(item.runtimeType)
        .add(' and is not a subtype of ')
        .addDescriptionOf(T);
    }
    return super.describeMismatch(item, mismatchDescription, matchState, verbose);
  }
}

class _EventListCriticalFieldsMatcher extends Matcher {
  _EventListCriticalFieldsMatcher(this._expected);

  final Iterable<BaseEventMatcher> _expected;

  @override
  bool matches(dynamic untypedItem, Map<dynamic, dynamic> matchState) {
    if (untypedItem is! Iterable<PointerEvent>) {
      return false;
    }
    final Iterable<PointerEvent> item = untypedItem;
    final Iterator<PointerEvent> iterator = item.iterator;
    if (item.length != _expected.length) {
      return false;
    }
    int i = 0;
    for (final BaseEventMatcher matcher in _expected) {
      iterator.moveNext();
      final Map<dynamic, dynamic> subState = <dynamic, dynamic>{};
      final PointerEvent actual = iterator.current;
      if (!matcher.matches(actual, subState)) {
        addStateInfo(matchState, <dynamic, dynamic>{
          'index': i,
          'expected': matcher.expected,
          'actual': actual,
          'matcher': matcher,
          'state': subState,
        });
        return false;
      }
      i++;
    }
    return true;
  }

  @override
  Description describe(Description description) {
    return description
      .add('event list (critical fields only) ')
      .addDescriptionOf(_expected);
  }

  @override
  Description describeMismatch(
    dynamic item,
    Description mismatchDescription,
    Map<dynamic, dynamic> matchState,
    bool verbose,
  ) {
    if (item is! Iterable<PointerEvent>) {
      return mismatchDescription
        .add('is type ${item.runtimeType} instead of Iterable<PointerEvent>');
    } else if (item.length != _expected.length) {
      return mismatchDescription
        .add('has length ${item.length} instead of ${_expected.length}');
    } else if (matchState['matcher'] == null) {
      return mismatchDescription
        .add('met unexpected fatal error');
    } else {
      mismatchDescription
        .add('has\n  ')
        .addDescriptionOf(matchState['actual'])
        .add("\nat index ${matchState['index']}, which doesn't match\n  ")
        .addDescriptionOf(matchState['expected'])
        .add('\nsince it ');
      final Description subDescription = StringDescription();
      final Matcher matcher = matchState['matcher'] as Matcher;
      matcher.describeMismatch(
        matchState['actual'],
        subDescription,
        matchState['state'] as Map<dynamic, dynamic>,
        verbose,
      );
      mismatchDescription.add(subDescription.toString());
      return mismatchDescription;
    }
  }
}

Matcher _equalToEventsOnCriticalFields(List<BaseEventMatcher> source) {
  return _EventListCriticalFieldsMatcher(source);
}
