tap_test.dart 7.25 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// 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 8
import 'package:test/test.dart';

9 10
import 'gesture_tester.dart';

11
class TestGestureArenaMember extends GestureArenaMember {
12
  @override
13
  void acceptGesture(int key) {}
14 15

  @override
16
  void rejectGesture(int key) {}
17 18
}

19
void main() {
20
  setUp(ensureGestureBinding);
21 22

  // Down/up pair 1: normal tap sequence
Ian Hickson's avatar
Ian Hickson committed
23
  const PointerDownEvent down1 = const PointerDownEvent(
24
    pointer: 1,
Ian Hickson's avatar
Ian Hickson committed
25
    position: const Point(10.0, 10.0)
26 27
  );

Ian Hickson's avatar
Ian Hickson committed
28
  const PointerUpEvent up1 = const PointerUpEvent(
29
    pointer: 1,
Ian Hickson's avatar
Ian Hickson committed
30
    position: const Point(11.0, 9.0)
31 32 33
  );

  // Down/up pair 2: normal tap sequence far away from pair 1
Ian Hickson's avatar
Ian Hickson committed
34
  const PointerDownEvent down2 = const PointerDownEvent(
35
    pointer: 2,
Ian Hickson's avatar
Ian Hickson committed
36
    position: const Point(30.0, 30.0)
37 38
  );

Ian Hickson's avatar
Ian Hickson committed
39
  const PointerUpEvent up2 = const PointerUpEvent(
40
    pointer: 2,
Ian Hickson's avatar
Ian Hickson committed
41
    position: const Point(31.0, 29.0)
42 43 44
  );

  // Down/move/up sequence 3: intervening motion
Ian Hickson's avatar
Ian Hickson committed
45
  const PointerDownEvent down3 = const PointerDownEvent(
46
    pointer: 3,
Ian Hickson's avatar
Ian Hickson committed
47
    position: const Point(10.0, 10.0)
48 49
  );

Ian Hickson's avatar
Ian Hickson committed
50
  const PointerMoveEvent move3 = const PointerMoveEvent(
51
    pointer: 3,
Ian Hickson's avatar
Ian Hickson committed
52
    position: const Point(25.0, 25.0)
53 54
  );

Ian Hickson's avatar
Ian Hickson committed
55
  const PointerUpEvent up3 = const PointerUpEvent(
56
    pointer: 3,
Ian Hickson's avatar
Ian Hickson committed
57
    position: const Point(25.0, 25.0)
58 59
  );

60
  testGesture('Should recognize tap', (GestureTester tester) {
61
    TapGestureRecognizer tap = new TapGestureRecognizer();
62 63 64 65 66 67

    bool tapRecognized = false;
    tap.onTap = () {
      tapRecognized = true;
    };

68
    tap.addPointer(down1);
69
    tester.closeArena(1);
70
    expect(tapRecognized, isFalse);
71
    tester.route(down1);
72 73
    expect(tapRecognized, isFalse);

74
    tester.route(up1);
75
    expect(tapRecognized, isTrue);
76
    GestureBinding.instance.gestureArena.sweep(1);
77 78 79 80 81
    expect(tapRecognized, isTrue);

    tap.dispose();
  });

82
  testGesture('No duplicate tap events', (GestureTester tester) {
83
    TapGestureRecognizer tap = new TapGestureRecognizer();
84 85 86 87 88 89 90

    int tapsRecognized = 0;
    tap.onTap = () {
      tapsRecognized++;
    };

    tap.addPointer(down1);
91
    tester.closeArena(1);
92
    expect(tapsRecognized, 0);
93
    tester.route(down1);
94 95
    expect(tapsRecognized, 0);

96
    tester.route(up1);
97
    expect(tapsRecognized, 1);
98
    GestureBinding.instance.gestureArena.sweep(1);
99 100 101
    expect(tapsRecognized, 1);

    tap.addPointer(down1);
102
    tester.closeArena(1);
103
    expect(tapsRecognized, 1);
104
    tester.route(down1);
105 106
    expect(tapsRecognized, 1);

107
    tester.route(up1);
108
    expect(tapsRecognized, 2);
109
    GestureBinding.instance.gestureArena.sweep(1);
110 111 112 113 114
    expect(tapsRecognized, 2);

    tap.dispose();
  });

115
  testGesture('Should not recognize two overlapping taps', (GestureTester tester) {
116
    TapGestureRecognizer tap = new TapGestureRecognizer();
117 118 119 120 121

    int tapsRecognized = 0;
    tap.onTap = () {
      tapsRecognized++;
    };
122

123
    tap.addPointer(down1);
124
    tester.closeArena(1);
125
    expect(tapsRecognized, 0);
126
    tester.route(down1);
127 128 129
    expect(tapsRecognized, 0);

    tap.addPointer(down2);
130
    tester.closeArena(2);
131
    expect(tapsRecognized, 0);
132
    tester.route(down1);
133 134 135
    expect(tapsRecognized, 0);


136
    tester.route(up1);
137
    expect(tapsRecognized, 1);
138
    GestureBinding.instance.gestureArena.sweep(1);
139 140
    expect(tapsRecognized, 1);

141
    tester.route(up2);
142
    expect(tapsRecognized, 1);
143
    GestureBinding.instance.gestureArena.sweep(2);
144
    expect(tapsRecognized, 1);
145 146 147 148

    tap.dispose();
  });

149
  testGesture('Distance cancels tap', (GestureTester tester) {
150
    TapGestureRecognizer tap = new TapGestureRecognizer();
151 152 153 154 155

    bool tapRecognized = false;
    tap.onTap = () {
      tapRecognized = true;
    };
Ian Hickson's avatar
Ian Hickson committed
156 157 158 159
    bool tapCanceled = false;
    tap.onTapCancel = () {
      tapCanceled = true;
    };
160 161

    tap.addPointer(down3);
162
    tester.closeArena(3);
163
    expect(tapRecognized, isFalse);
Ian Hickson's avatar
Ian Hickson committed
164
    expect(tapCanceled, isFalse);
165
    tester.route(down3);
166
    expect(tapRecognized, isFalse);
Ian Hickson's avatar
Ian Hickson committed
167
    expect(tapCanceled, isFalse);
168

169
    tester.route(move3);
170
    expect(tapRecognized, isFalse);
Ian Hickson's avatar
Ian Hickson committed
171
    expect(tapCanceled, isTrue);
172
    tester.route(up3);
173
    expect(tapRecognized, isFalse);
Ian Hickson's avatar
Ian Hickson committed
174
    expect(tapCanceled, isTrue);
175
    GestureBinding.instance.gestureArena.sweep(3);
176
    expect(tapRecognized, isFalse);
Ian Hickson's avatar
Ian Hickson committed
177
    expect(tapCanceled, isTrue);
178

179 180 181
    tap.dispose();
  });

182
  testGesture('Timeout does not cancel tap', (GestureTester tester) {
183
    TapGestureRecognizer tap = new TapGestureRecognizer();
184 185 186 187 188 189

    bool tapRecognized = false;
    tap.onTap = () {
      tapRecognized = true;
    };

190 191 192 193 194 195 196 197 198 199 200 201
    tap.addPointer(down1);
    tester.closeArena(1);
    expect(tapRecognized, isFalse);
    tester.route(down1);
    expect(tapRecognized, isFalse);

    tester.async.elapse(new Duration(milliseconds: 500));
    expect(tapRecognized, isFalse);
    tester.route(up1);
    expect(tapRecognized, isTrue);
    GestureBinding.instance.gestureArena.sweep(1);
    expect(tapRecognized, isTrue);
202 203 204 205

    tap.dispose();
  });

206
  testGesture('Should yield to other arena members', (GestureTester tester) {
207
    TapGestureRecognizer tap = new TapGestureRecognizer();
208 209 210 211 212 213 214 215

    bool tapRecognized = false;
    tap.onTap = () {
      tapRecognized = true;
    };

    tap.addPointer(down1);
    TestGestureArenaMember member = new TestGestureArenaMember();
216 217
    GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
    GestureBinding.instance.gestureArena.hold(1);
218
    tester.closeArena(1);
219
    expect(tapRecognized, isFalse);
220
    tester.route(down1);
221 222
    expect(tapRecognized, isFalse);

223
    tester.route(up1);
224
    expect(tapRecognized, isFalse);
225
    GestureBinding.instance.gestureArena.sweep(1);
226 227 228 229 230 231 232 233
    expect(tapRecognized, isFalse);

    entry.resolve(GestureDisposition.accepted);
    expect(tapRecognized, isFalse);

    tap.dispose();
  });

234
  testGesture('Should trigger on release of held arena', (GestureTester tester) {
235
    TapGestureRecognizer tap = new TapGestureRecognizer();
236 237 238 239 240 241 242 243

    bool tapRecognized = false;
    tap.onTap = () {
      tapRecognized = true;
    };

    tap.addPointer(down1);
    TestGestureArenaMember member = new TestGestureArenaMember();
244 245
    GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
    GestureBinding.instance.gestureArena.hold(1);
246
    tester.closeArena(1);
247
    expect(tapRecognized, isFalse);
248
    tester.route(down1);
249 250
    expect(tapRecognized, isFalse);

251
    tester.route(up1);
252
    expect(tapRecognized, isFalse);
253
    GestureBinding.instance.gestureArena.sweep(1);
254 255 256
    expect(tapRecognized, isFalse);

    entry.resolve(GestureDisposition.rejected);
257
    tester.async.flushMicrotasks();
258 259 260 261
    expect(tapRecognized, isTrue);

    tap.dispose();
  });
262

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
  testGesture('Should log exceptions from callbacks', (GestureTester tester) {
    TapGestureRecognizer tap = new TapGestureRecognizer();

    tap.onTap = () {
      throw new Exception(test);
    };

    FlutterExceptionHandler previousErrorHandler = FlutterError.onError;
    bool gotError = false;
    FlutterError.onError = (FlutterErrorDetails details) {
      gotError = true;
    };

    tap.addPointer(down1);
    tester.closeArena(1);
    tester.route(down1);
    expect(gotError, isFalse);

    tester.route(up1);
    expect(gotError, isTrue);

    FlutterError.onError = previousErrorHandler;
    tap.dispose();
  });
287
}