pointer_router_test.dart 6.88 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
import 'package:flutter/foundation.dart';
6
import 'package:flutter/gestures.dart';
7
import 'package:flutter_test/flutter_test.dart';
8 9 10 11

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

16 17
    final TestPointer pointer2 = TestPointer(2);
    final TestPointer pointer3 = TestPointer(3);
18

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

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

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

    bool firstCallbackRan = false;
53
    final PointerRouter router = PointerRouter();
54 55 56 57 58
    router.addGlobalRoute((PointerEvent event) {
      firstCallbackRan = true;
      router.addGlobalRoute(secondCallback);
    });

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

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

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

  test('Per-pointer callbacks happen before global callbacks', () {
98
    final List<String> log = <String>[];
99
    final PointerRouter router = PointerRouter();
100 101 102 103 104 105 106 107 108 109 110 111
    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');
    });
112
    final TestPointer pointer2 = TestPointer(2);
113
    router.route(pointer2.down(Offset.zero));
114 115 116 117 118 119 120
    expect(log, equals(<String>[
      'per-pointer 1',
      'per-pointer 2',
      'global 1',
      'global 2',
    ]));
  });
121 122

  test('Exceptions do not stop pointer routing', () {
123
    final List<String> log = <String>[];
124
    final PointerRouter router = PointerRouter();
125 126 127 128 129
    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
130
      throw 'Having a bad day!';
131 132 133 134 135
    });
    router.addRoute(2, (PointerEvent event) {
      log.add('per-pointer 3');
    });

136
    final FlutterExceptionHandler? previousErrorHandler = FlutterError.onError;
137 138 139 140
    FlutterError.onError = (FlutterErrorDetails details) {
      log.add('error report');
    };

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

    FlutterError.onError = previousErrorHandler;
  });
152

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

164 165 166 167
  test('Should transform events', () {
    final List<PointerEvent> events = <PointerEvent>[];
    final List<PointerEvent> globalEvents = <PointerEvent>[];
    final PointerRouter router = PointerRouter();
168
    final Matrix4 transform = (Matrix4.identity()..scale(1 / 2.0, 1 / 2.0, 1.0)).multiplied(Matrix4.translationValues(-10, -30, 0));
169 170 171 172 173 174 175 176 177

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

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

178
    final TestPointer pointer1 = TestPointer();
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
    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));
  });
212
}