pointer_router_test.dart 6.95 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
Ian Hickson's avatar
Ian Hickson committed
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
// @dart = 2.8

Adam Barth's avatar
Adam Barth committed
7
import 'package:flutter_test/flutter_test.dart';
8
import 'package:flutter/foundation.dart';
9
import 'package:flutter/gestures.dart';
10
import 'package:vector_math/vector_math_64.dart';
11 12 13 14

void main() {
  test('Should route pointers', () {
    bool callbackRan = false;
Ian Hickson's avatar
Ian Hickson committed
15
    void callback(PointerEvent event) {
16 17 18
      callbackRan = true;
    }

19 20
    final TestPointer pointer2 = TestPointer(2);
    final TestPointer pointer3 = TestPointer(3);
21

22
    final PointerRouter router = PointerRouter();
23
    router.addRoute(3, callback);
24
    router.route(pointer2.down(Offset.zero));
25
    expect(callbackRan, isFalse);
26
    router.route(pointer3.down(Offset.zero));
27 28 29
    expect(callbackRan, isTrue);
    callbackRan = false;
    router.removeRoute(3, callback);
30
    router.route(pointer3.up());
31 32
    expect(callbackRan, isFalse);
  });
33 34 35 36 37 38

  test('Supports re-entrant cancellation', () {
    bool callbackRan = false;
    void callback(PointerEvent event) {
      callbackRan = true;
    }
39
    final PointerRouter router = PointerRouter();
40 41 42 43
    router.addRoute(2, (PointerEvent event) {
      router.removeRoute(2, callback);
    });
    router.addRoute(2, callback);
44
    final TestPointer pointer2 = TestPointer(2);
45
    router.route(pointer2.down(Offset.zero));
46 47
    expect(callbackRan, isFalse);
  });
48 49 50 51 52 53 54 55

  test('Supports global callbacks', () {
    bool secondCallbackRan = false;
    void secondCallback(PointerEvent event) {
      secondCallbackRan = true;
    }

    bool firstCallbackRan = false;
56
    final PointerRouter router = PointerRouter();
57 58 59 60 61
    router.addGlobalRoute((PointerEvent event) {
      firstCallbackRan = true;
      router.addGlobalRoute(secondCallback);
    });

62
    final TestPointer pointer2 = TestPointer(2);
63
    router.route(pointer2.down(Offset.zero));
64 65 66 67 68 69 70 71 72
    expect(firstCallbackRan, isTrue);
    expect(secondCallbackRan, isFalse);
  });

  test('Supports re-entrant global cancellation', () {
    bool callbackRan = false;
    void callback(PointerEvent event) {
      callbackRan = true;
    }
73
    final PointerRouter router = PointerRouter();
74 75 76 77
    router.addGlobalRoute((PointerEvent event) {
      router.removeGlobalRoute(callback);
    });
    router.addGlobalRoute(callback);
78
    final TestPointer pointer2 = TestPointer(2);
79
    router.route(pointer2.down(Offset.zero));
80 81 82 83 84 85 86 87
    expect(callbackRan, isFalse);
  });

  test('Per-pointer callbacks cannot re-entrantly add global routes', () {
    bool callbackRan = false;
    void callback(PointerEvent event) {
      callbackRan = true;
    }
88
    final PointerRouter router = PointerRouter();
89 90 91 92 93
    bool perPointerCallbackRan = false;
    router.addRoute(2, (PointerEvent event) {
      perPointerCallbackRan = true;
      router.addGlobalRoute(callback);
    });
94
    final TestPointer pointer2 = TestPointer(2);
95
    router.route(pointer2.down(Offset.zero));
96 97 98 99 100
    expect(perPointerCallbackRan, isTrue);
    expect(callbackRan, isFalse);
  });

  test('Per-pointer callbacks happen before global callbacks', () {
101
    final List<String> log = <String>[];
102
    final PointerRouter router = PointerRouter();
103 104 105 106 107 108 109 110 111 112 113 114
    router.addGlobalRoute((PointerEvent event) {
      log.add('global 1');
    });
    router.addRoute(2, (PointerEvent event) {
      log.add('per-pointer 1');
    });
    router.addGlobalRoute((PointerEvent event) {
      log.add('global 2');
    });
    router.addRoute(2, (PointerEvent event) {
      log.add('per-pointer 2');
    });
115
    final TestPointer pointer2 = TestPointer(2);
116
    router.route(pointer2.down(Offset.zero));
117 118 119 120 121 122 123
    expect(log, equals(<String>[
      'per-pointer 1',
      'per-pointer 2',
      'global 1',
      'global 2',
    ]));
  });
124 125

  test('Exceptions do not stop pointer routing', () {
126
    final List<String> log = <String>[];
127
    final PointerRouter router = PointerRouter();
128 129 130 131 132
    router.addRoute(2, (PointerEvent event) {
      log.add('per-pointer 1');
    });
    router.addRoute(2, (PointerEvent event) {
      log.add('per-pointer 2');
Ian Hickson's avatar
Ian Hickson committed
133
      throw 'Having a bad day!';
134 135 136 137 138
    });
    router.addRoute(2, (PointerEvent event) {
      log.add('per-pointer 3');
    });

139
    final FlutterExceptionHandler previousErrorHandler = FlutterError.onError;
140 141 142 143
    FlutterError.onError = (FlutterErrorDetails details) {
      log.add('error report');
    };

144
    final TestPointer pointer2 = TestPointer(2);
145
    router.route(pointer2.down(Offset.zero));
146 147 148 149 150 151 152 153 154
    expect(log, equals(<String>[
      'per-pointer 1',
      'per-pointer 2',
      'error report',
      'per-pointer 3',
    ]));

    FlutterError.onError = previousErrorHandler;
  });
155

156 157 158 159 160 161 162 163 164 165 166
  test('Exceptions include router, route & event', () {
    try {
      final PointerRouter router = PointerRouter();
      router.addRoute(2, (PointerEvent event) => throw 'Pointer exception');
    } catch (e) {
      expect(e, contains('router: Instance of \'PointerRouter\''));
      expect(e, contains('route: Closure: (PointerEvent) => Null'));
      expect(e, contains('event: PointerDownEvent#[a-zA-Z0-9]{5}(position: Offset(0.0, 0.0))'));
    }
  });

167 168 169 170
  test('Should transform events', () {
    final List<PointerEvent> events = <PointerEvent>[];
    final List<PointerEvent> globalEvents = <PointerEvent>[];
    final PointerRouter router = PointerRouter();
171
    final Matrix4 transform = (Matrix4.identity()..scale(1 / 2.0, 1 / 2.0, 1.0)).multiplied(Matrix4.translationValues(-10, -30, 0));
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214

    router.addRoute(1, (PointerEvent event) {
      events.add(event);
    }, transform);

    router.addGlobalRoute((PointerEvent event) {
      globalEvents.add(event);
    }, transform);

    final TestPointer pointer1 = TestPointer(1);
    const Offset firstPosition = Offset(16, 36);
    router.route(pointer1.down(firstPosition));

    expect(events.single.transform, transform);
    expect(events.single.position, firstPosition);
    expect(events.single.delta, Offset.zero);
    expect(events.single.localPosition, const Offset(3, 3));
    expect(events.single.localDelta, Offset.zero);

    expect(globalEvents.single.transform, transform);
    expect(globalEvents.single.position, firstPosition);
    expect(globalEvents.single.delta, Offset.zero);
    expect(globalEvents.single.localPosition, const Offset(3, 3));
    expect(globalEvents.single.localDelta, Offset.zero);

    events.clear();
    globalEvents.clear();

    const Offset newPosition = Offset(20, 40);
    router.route(pointer1.move(newPosition));

    expect(events.single.transform, transform);
    expect(events.single.position, newPosition);
    expect(events.single.delta, newPosition - firstPosition);
    expect(events.single.localPosition, const Offset(5, 5));
    expect(events.single.localDelta, const Offset(2, 2));

    expect(globalEvents.single.transform, transform);
    expect(globalEvents.single.position, newPosition);
    expect(globalEvents.single.delta, newPosition - firstPosition);
    expect(globalEvents.single.localPosition, const Offset(5, 5));
    expect(globalEvents.single.localDelta, const Offset(2, 2));
  });
215
}