// 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/rendering.dart';
import 'package:flutter/gestures.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]) {
    ui.window.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.
    ui.window.onPointerDataPacket!(ui.PointerDataPacket(data: <ui.PointerData>[
      _pointerData(PointerChange.add, Offset.zero),
    ]));
    addTearDown(() => dispatchRemoveDevice());

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

    // Pointer hovers the annotation.
    ui.window.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.
    ui.window.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.
    ui.window.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();
  });

  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.
    ui.window.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(position: Offset.zero)),
      EventMatcher<PointerHoverEvent>(const PointerHoverEvent(position: Offset(0.0, 1.0))),
    ]));
    expect(_mouseTracker.mouseIsConnected, isTrue);
    events.clear();

    // The second mouse is added on the annotation.
    ui.window.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.
    ui.window.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.
    ui.window.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.
    ui.window.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.
    ui.window.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.
    ui.window.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);

    ui.window.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();

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

    ui.window.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.
    ui.window.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.
    ui.window.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;
    ui.window.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.
    ui.window.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;
    ui.window.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;
    ui.window.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;
    ui.window.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
    ui.window.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;
    ui.window.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;
    ui.window.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;
    ui.window.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;
    ui.window.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;
    ui.window.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;
    ui.window.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;
    ui.window.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 * ui.window.devicePixelRatio,
    physicalY: logicalPosition.dy * ui.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 expected) : 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);
}
