input_pipeline/gestures/
secondary_tap.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::gesture_arena::{
6    self, DetailedReasonFloat, DetailedReasonInt, DetailedReasonUint, ExamineEventResult,
7    ProcessBufferedEventsResult, Reason, RecognizedGesture, SECONDARY_BUTTON, TouchpadEvent,
8    VerifyEventResult,
9};
10use crate::mouse_binding::{MouseEvent, MouseLocation, MousePhase, RelativeLocation};
11use crate::utils::{Position, euclidean_distance};
12use fuchsia_sync::Mutex;
13
14use maplit::hashset;
15
16/// The initial state of this recognizer, before a secondary tap has been
17/// detected.
18#[derive(Debug)]
19pub(super) struct InitialContender {
20    /// The maximum displacement that a detected finger can withstand to still
21    /// be considered a secondary tap. Measured in millimeters.
22    pub(super) max_finger_displacement_in_mm: f32,
23
24    /// The maximum time that can elapse between two fingers down and fingers up
25    /// to be considered a secondary tap gesture.
26    pub(super) max_time_elapsed: zx::MonotonicDuration,
27}
28
29impl InitialContender {
30    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
31    fn into_one_finger_contact_contender(
32        self: Box<Self>,
33        one_finger_contact_event: TouchpadEvent,
34    ) -> Box<dyn gesture_arena::Contender> {
35        Box::new(OneFingerContactContender {
36            one_finger_contact_event,
37            max_finger_displacement_in_mm: self.max_finger_displacement_in_mm,
38            max_time_elapsed: self.max_time_elapsed,
39        })
40    }
41
42    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
43    fn into_two_finger_contacts_contender(
44        self: Box<Self>,
45        two_finger_contacts_event: TouchpadEvent,
46    ) -> Box<dyn gesture_arena::Contender> {
47        Box::new(TwoFingerContactsContender {
48            two_finger_contacts_event,
49            max_finger_displacement_in_mm: self.max_finger_displacement_in_mm,
50            max_time_elapsed: self.max_time_elapsed,
51        })
52    }
53}
54
55impl gesture_arena::Contender for InitialContender {
56    fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
57        let num_pressed_buttons = event.pressed_buttons.len();
58        if num_pressed_buttons != 0 {
59            return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
60                criterion: "num_pressed_buttons",
61                min: Some(0),
62                max: Some(0),
63                actual: num_pressed_buttons,
64            }));
65        }
66
67        let num_contacts = event.contacts.len();
68        match num_contacts {
69            1 => {
70                ExamineEventResult::Contender(self.into_one_finger_contact_contender(event.clone()))
71            }
72            2 => ExamineEventResult::Contender(
73                self.into_two_finger_contacts_contender(event.clone()),
74            ),
75            0 | _ => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
76                criterion: "num_contacts",
77                min: Some(1),
78                max: Some(2),
79                actual: num_contacts,
80            })),
81        }
82    }
83
84    fn start_from_idle(&self) -> bool {
85        true
86    }
87}
88
89/// The state when this recognizer has detected a single finger down.
90#[derive(Debug)]
91struct OneFingerContactContender {
92    /// The TouchpadEvent when a finger down was first detected.
93    one_finger_contact_event: TouchpadEvent,
94
95    /// The maximum displacement that a detected finger can withstand to still
96    /// be considered a tap. Measured in millimeters.
97    max_finger_displacement_in_mm: f32,
98
99    /// The maximum time that can elapse between two fingers down and fingers up
100    /// to be considered a secondary tap gesture.
101    max_time_elapsed: zx::MonotonicDuration,
102}
103
104impl OneFingerContactContender {
105    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
106    fn into_two_finger_contacts_contender(
107        self: Box<Self>,
108        two_finger_contacts_event: TouchpadEvent,
109    ) -> Box<dyn gesture_arena::Contender> {
110        Box::new(TwoFingerContactsContender {
111            two_finger_contacts_event,
112            max_finger_displacement_in_mm: self.max_finger_displacement_in_mm,
113            max_time_elapsed: self.max_time_elapsed,
114        })
115    }
116}
117
118impl gesture_arena::Contender for OneFingerContactContender {
119    fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
120        let elapsed_time = event.timestamp - self.one_finger_contact_event.timestamp;
121        if elapsed_time >= self.max_time_elapsed {
122            return ExamineEventResult::Mismatch(Reason::DetailedInt(DetailedReasonInt {
123                criterion: "elapsed_time_micros",
124                min: None,
125                max: Some(self.max_time_elapsed.into_micros()),
126                actual: elapsed_time.into_micros(),
127            }));
128        }
129
130        let num_pressed_buttons = event.pressed_buttons.len();
131        if num_pressed_buttons != 0 {
132            return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
133                criterion: "num_pressed_buttons",
134                min: Some(0),
135                max: Some(0),
136                actual: num_pressed_buttons,
137            }));
138        }
139
140        let num_contacts = event.contacts.len();
141        match num_contacts {
142            1 => {
143                let displacement_mm = euclidean_distance(
144                    position_from_event(event, 0),
145                    position_from_event(&self.one_finger_contact_event, 0),
146                );
147                if displacement_mm >= self.max_finger_displacement_in_mm {
148                    return ExamineEventResult::Mismatch(Reason::DetailedFloat(
149                        DetailedReasonFloat {
150                            criterion: "displacement_mm",
151                            min: None,
152                            max: Some(self.max_finger_displacement_in_mm),
153                            actual: displacement_mm,
154                        },
155                    ));
156                }
157                ExamineEventResult::Contender(self)
158            }
159            2 => {
160                let displacement_mm = euclidean_distance(
161                    position_from_event(event, 0),
162                    position_from_event(&self.one_finger_contact_event, 0),
163                );
164                if displacement_mm >= self.max_finger_displacement_in_mm {
165                    return ExamineEventResult::Mismatch(Reason::DetailedFloat(
166                        DetailedReasonFloat {
167                            criterion: "displacement_mm",
168                            min: None,
169                            max: Some(self.max_finger_displacement_in_mm),
170                            actual: displacement_mm,
171                        },
172                    ));
173                }
174                ExamineEventResult::Contender(
175                    self.into_two_finger_contacts_contender(event.clone()),
176                )
177            }
178            0 | _ => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
179                criterion: "num_contacts",
180                min: Some(1),
181                max: Some(2),
182                actual: num_contacts,
183            })),
184        }
185    }
186}
187
188/// The state when this recognizer has detected two fingers down.
189#[derive(Debug)]
190struct TwoFingerContactsContender {
191    /// The TouchpadEvent when two fingers were first detected.
192    two_finger_contacts_event: TouchpadEvent,
193
194    /// The maximum displacement that a detected finger can withstand to still
195    /// be considered a tap. Measured in millimeters.
196    max_finger_displacement_in_mm: f32,
197
198    /// The maximum time that can elapse between two fingers down and fingers up
199    /// to be considered a secondary tap gesture.
200    max_time_elapsed: zx::MonotonicDuration,
201}
202
203impl TwoFingerContactsContender {
204    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
205    fn into_one_finger_raised_contender(self: Box<Self>) -> Box<dyn gesture_arena::Contender> {
206        Box::new(OneFingerRaisedContender {
207            two_finger_contacts_event: self.two_finger_contacts_event,
208            max_finger_displacement_in_mm: self.max_finger_displacement_in_mm,
209            max_time_elapsed: self.max_time_elapsed,
210        })
211    }
212
213    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
214    fn into_matched_contender(
215        self: Box<Self>,
216        no_contacts_event: TouchpadEvent,
217    ) -> Box<dyn gesture_arena::MatchedContender> {
218        Box::new(MatchedContender {
219            two_finger_contacts_event: self.two_finger_contacts_event,
220            no_contacts_event,
221            max_time_elapsed: self.max_time_elapsed,
222        })
223    }
224}
225
226impl gesture_arena::Contender for TwoFingerContactsContender {
227    fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
228        let elapsed_time = event.timestamp - self.two_finger_contacts_event.timestamp;
229        if elapsed_time >= self.max_time_elapsed {
230            return ExamineEventResult::Mismatch(Reason::DetailedInt(DetailedReasonInt {
231                criterion: "elapsed_time_micros",
232                min: None,
233                max: Some(self.max_time_elapsed.into_micros()),
234                actual: elapsed_time.into_micros(),
235            }));
236        }
237
238        let num_pressed_buttons = event.pressed_buttons.len();
239        if num_pressed_buttons != 0 {
240            return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
241                criterion: "num_pressed_buttons",
242                min: Some(0),
243                max: Some(0),
244                actual: num_pressed_buttons,
245            }));
246        }
247
248        let num_contacts = u8::try_from(event.contacts.len()).unwrap_or(u8::MAX);
249        match num_contacts {
250            0 => ExamineEventResult::MatchedContender(self.into_matched_contender(event.clone())),
251            1 => {
252                match &self
253                    .two_finger_contacts_event
254                    .clone()
255                    .contacts
256                    .into_iter()
257                    .find(|contact| contact.id == event.contacts[0].id)
258                {
259                    Some(contact) => {
260                        let displacement_mm =
261                            euclidean_distance(position_from_event(event, 0), contact.position);
262                        if displacement_mm >= self.max_finger_displacement_in_mm {
263                            return ExamineEventResult::Mismatch(Reason::DetailedFloat(
264                                DetailedReasonFloat {
265                                    criterion: "displacement_mm",
266                                    min: None,
267                                    max: Some(self.max_finger_displacement_in_mm),
268                                    actual: displacement_mm,
269                                },
270                            ));
271                        }
272                    }
273                    None => {
274                        return ExamineEventResult::Mismatch(Reason::Basic(
275                            "remaining contact id differs from initial two finger contacts",
276                        ));
277                    }
278                }
279
280                ExamineEventResult::Contender(self.into_one_finger_raised_contender())
281            }
282            2 => {
283                // Acceptable displacement on the first touch contact.
284                let displacement_mm = euclidean_distance(
285                    position_from_event(event, 0),
286                    position_from_event(&self.two_finger_contacts_event, 0),
287                );
288                if displacement_mm >= self.max_finger_displacement_in_mm {
289                    return ExamineEventResult::Mismatch(Reason::DetailedFloat(
290                        DetailedReasonFloat {
291                            criterion: "displacement_mm",
292                            min: None,
293                            max: Some(self.max_finger_displacement_in_mm),
294                            actual: displacement_mm,
295                        },
296                    ));
297                }
298
299                // Acceptable displacement on the second touch contact.
300                let displacement_mm = euclidean_distance(
301                    position_from_event(event, 1),
302                    position_from_event(&self.two_finger_contacts_event, 1),
303                );
304                if displacement_mm >= self.max_finger_displacement_in_mm {
305                    return ExamineEventResult::Mismatch(Reason::DetailedFloat(
306                        DetailedReasonFloat {
307                            criterion: "displacement_mm",
308                            min: None,
309                            max: Some(self.max_finger_displacement_in_mm),
310                            actual: displacement_mm,
311                        },
312                    ));
313                }
314
315                ExamineEventResult::Contender(self)
316            }
317            3.. => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
318                criterion: "num_contacts",
319                min: Some(0),
320                max: Some(2),
321                actual: usize::from(num_contacts),
322            })),
323        }
324    }
325}
326
327/// The state when this recognizer has already detected two fingers down,
328/// and one of those fingers has been raised.
329#[derive(Debug)]
330struct OneFingerRaisedContender {
331    /// The TouchpadEvent when two fingers were first detected.
332    two_finger_contacts_event: TouchpadEvent,
333
334    /// The maximum displacement that a detected finger can withstand to still
335    /// be considered a tap. Measured in millimeters.
336    max_finger_displacement_in_mm: f32,
337
338    /// The maximum time that can elapse between two fingers down and fingers up
339    /// to be considered a secondary tap gesture.
340    max_time_elapsed: zx::MonotonicDuration,
341}
342
343impl OneFingerRaisedContender {
344    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
345    fn into_matched_contender(
346        self: Box<Self>,
347        no_contacts_event: TouchpadEvent,
348    ) -> Box<dyn gesture_arena::MatchedContender> {
349        Box::new(MatchedContender {
350            two_finger_contacts_event: self.two_finger_contacts_event,
351            no_contacts_event,
352            max_time_elapsed: self.max_time_elapsed,
353        })
354    }
355}
356
357impl gesture_arena::Contender for OneFingerRaisedContender {
358    fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
359        let elapsed_time = event.timestamp - self.two_finger_contacts_event.timestamp;
360        if elapsed_time >= self.max_time_elapsed {
361            return ExamineEventResult::Mismatch(Reason::DetailedInt(DetailedReasonInt {
362                criterion: "elapsed_time_micros",
363                min: None,
364                max: Some(self.max_time_elapsed.into_micros()),
365                actual: elapsed_time.into_micros(),
366            }));
367        }
368
369        let num_pressed_buttons = event.pressed_buttons.len();
370        if num_pressed_buttons != 0 {
371            return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
372                criterion: "num_pressed_buttons",
373                min: Some(0),
374                max: Some(0),
375                actual: num_pressed_buttons,
376            }));
377        }
378
379        let num_contacts = u8::try_from(event.contacts.len()).unwrap_or(u8::MAX);
380        match num_contacts {
381            0 => ExamineEventResult::MatchedContender(self.into_matched_contender(event.clone())),
382            1 => {
383                match &self
384                    .two_finger_contacts_event
385                    .clone()
386                    .contacts
387                    .into_iter()
388                    .find(|contact| contact.id == event.contacts[0].id)
389                {
390                    Some(contact) => {
391                        let displacement_mm =
392                            euclidean_distance(position_from_event(event, 0), contact.position);
393                        if displacement_mm >= self.max_finger_displacement_in_mm {
394                            return ExamineEventResult::Mismatch(Reason::DetailedFloat(
395                                DetailedReasonFloat {
396                                    criterion: "displacement_mm",
397                                    min: None,
398                                    max: Some(self.max_finger_displacement_in_mm),
399                                    actual: displacement_mm,
400                                },
401                            ));
402                        }
403                    }
404                    None => {
405                        return ExamineEventResult::Mismatch(Reason::Basic(
406                            "remaining contact id differs from initial two finger contacts",
407                        ));
408                    }
409                }
410
411                ExamineEventResult::Contender(self)
412            }
413            2.. => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
414                criterion: "num_contacts",
415                min: Some(0),
416                max: Some(1),
417                actual: usize::from(num_contacts),
418            })),
419        }
420    }
421}
422
423/// The state when this recognizer has detected a secondary tap, but the
424/// gesture arena has not declared this recognizer the winner.
425#[derive(Debug)]
426struct MatchedContender {
427    /// The TouchpadEvent when two fingers were first detected.
428    two_finger_contacts_event: TouchpadEvent,
429
430    /// The TouchpadEvent when two fingers, previously detected, were released.
431    no_contacts_event: TouchpadEvent,
432
433    /// The maximum time that can elapse between two fingers down and fingers up
434    /// to be considered a secondary tap gesture.
435    max_time_elapsed: zx::MonotonicDuration,
436}
437
438impl gesture_arena::MatchedContender for MatchedContender {
439    fn verify_event(self: Box<Self>, event: &TouchpadEvent) -> VerifyEventResult {
440        let elapsed_time = event.timestamp - self.two_finger_contacts_event.timestamp;
441        if elapsed_time >= self.max_time_elapsed {
442            return VerifyEventResult::Mismatch(Reason::DetailedInt(DetailedReasonInt {
443                criterion: "elapsed_time_micros",
444                min: None,
445                max: Some(self.max_time_elapsed.into_micros()),
446                actual: elapsed_time.into_micros(),
447            }));
448        }
449
450        let num_contacts = event.contacts.len();
451        if num_contacts != 0 {
452            return VerifyEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
453                criterion: "num_contacts",
454                min: Some(0),
455                max: Some(0),
456                actual: num_contacts,
457            }));
458        }
459
460        let num_pressed_buttons = event.pressed_buttons.len();
461        if num_pressed_buttons != 0 {
462            return VerifyEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
463                criterion: "num_pressed_buttons",
464                min: Some(0),
465                max: Some(0),
466                actual: num_pressed_buttons,
467            }));
468        }
469
470        VerifyEventResult::MatchedContender(self)
471    }
472
473    fn process_buffered_events(
474        self: Box<Self>,
475        _events: Vec<TouchpadEvent>,
476    ) -> ProcessBufferedEventsResult {
477        ProcessBufferedEventsResult {
478            generated_events: vec![
479                gesture_arena::MouseEvent {
480                    timestamp: self.two_finger_contacts_event.timestamp,
481                    mouse_data: MouseEvent {
482                        location: MouseLocation::Relative(RelativeLocation {
483                            millimeters: Position::zero(),
484                        }),
485                        wheel_delta_v: None,
486                        wheel_delta_h: None,
487                        phase: MousePhase::Down,
488                        affected_buttons: hashset! {SECONDARY_BUTTON},
489                        pressed_buttons: hashset! {SECONDARY_BUTTON},
490                        is_precision_scroll: None,
491                        wake_lease: Mutex::new(None),
492                    },
493                },
494                gesture_arena::MouseEvent {
495                    timestamp: self.no_contacts_event.timestamp,
496                    mouse_data: MouseEvent {
497                        location: MouseLocation::Relative(RelativeLocation {
498                            millimeters: Position::zero(),
499                        }),
500                        wheel_delta_v: None,
501                        wheel_delta_h: None,
502                        phase: MousePhase::Up,
503                        affected_buttons: hashset! {SECONDARY_BUTTON},
504                        pressed_buttons: hashset! {},
505                        is_precision_scroll: None,
506                        wake_lease: Mutex::new(None),
507                    },
508                },
509            ],
510            winner: None,
511            recognized_gesture: RecognizedGesture::SecondaryTap,
512        }
513    }
514}
515
516/// This function returns the position associated with the touch contact at the
517/// given index from a TouchpadEvent.
518fn position_from_event(event: &TouchpadEvent, index: usize) -> Position {
519    event.contacts[index].position
520}
521
522#[cfg(test)]
523mod tests {
524    use super::*;
525    use crate::gestures::gesture_arena::{Contender, MatchedContender as _};
526    use crate::testing_utilities::create_touch_contact;
527    use assert_matches::assert_matches;
528    use std::any::TypeId;
529
530    const MAX_TIME_ELAPSED: zx::MonotonicDuration = zx::MonotonicDuration::from_nanos(10000);
531    const MAX_FINGER_DISPLACEMENT_IN_MM: f32 = 10.0;
532    const HALF_MOTION: f32 = MAX_FINGER_DISPLACEMENT_IN_MM / 2.0;
533
534    fn get_initial_contender() -> Box<InitialContender> {
535        Box::new(InitialContender {
536            max_finger_displacement_in_mm: MAX_FINGER_DISPLACEMENT_IN_MM,
537            max_time_elapsed: MAX_TIME_ELAPSED,
538        })
539    }
540
541    fn get_one_finger_contact_contender() -> Box<OneFingerContactContender> {
542        Box::new(OneFingerContactContender {
543            max_finger_displacement_in_mm: MAX_FINGER_DISPLACEMENT_IN_MM,
544            max_time_elapsed: MAX_TIME_ELAPSED,
545            one_finger_contact_event: TouchpadEvent {
546                contacts: vec![create_touch_contact(0, Position::zero())],
547                timestamp: zx::MonotonicInstant::from_nanos(0),
548                pressed_buttons: vec![],
549                filtered_palm_contacts: vec![],
550            },
551        })
552    }
553
554    fn get_two_finger_contacts_contender() -> Box<TwoFingerContactsContender> {
555        Box::new(TwoFingerContactsContender {
556            max_finger_displacement_in_mm: MAX_FINGER_DISPLACEMENT_IN_MM,
557            max_time_elapsed: MAX_TIME_ELAPSED,
558            two_finger_contacts_event: TouchpadEvent {
559                contacts: vec![
560                    create_touch_contact(0, Position::zero()),
561                    create_touch_contact(1, Position::zero()),
562                ],
563                timestamp: zx::MonotonicInstant::from_nanos(0),
564                pressed_buttons: vec![],
565                filtered_palm_contacts: vec![],
566            },
567        })
568    }
569
570    fn get_one_finger_raised_contender() -> Box<OneFingerRaisedContender> {
571        Box::new(OneFingerRaisedContender {
572            max_finger_displacement_in_mm: MAX_FINGER_DISPLACEMENT_IN_MM,
573            max_time_elapsed: MAX_TIME_ELAPSED,
574            two_finger_contacts_event: TouchpadEvent {
575                contacts: vec![
576                    create_touch_contact(0, Position::zero()),
577                    create_touch_contact(1, Position::zero()),
578                ],
579                timestamp: zx::MonotonicInstant::from_nanos(0),
580                pressed_buttons: vec![],
581                filtered_palm_contacts: vec![],
582            },
583        })
584    }
585
586    fn get_matched_contender() -> Box<MatchedContender> {
587        Box::new(MatchedContender {
588            two_finger_contacts_event: TouchpadEvent {
589                contacts: vec![
590                    create_touch_contact(0, Position::zero()),
591                    create_touch_contact(1, Position::zero()),
592                ],
593                timestamp: zx::MonotonicInstant::from_nanos(0),
594                pressed_buttons: vec![],
595                filtered_palm_contacts: vec![],
596            },
597            no_contacts_event: TouchpadEvent {
598                contacts: vec![],
599                timestamp: zx::MonotonicInstant::from_nanos(123),
600                pressed_buttons: vec![],
601                filtered_palm_contacts: vec![],
602            },
603            max_time_elapsed: MAX_TIME_ELAPSED,
604        })
605    }
606
607    fn assert_contender(result: ExamineEventResult, type_id: TypeId) {
608        match result {
609            ExamineEventResult::Contender(boxed) => {
610                assert_eq!((&*boxed).as_any().type_id(), type_id);
611            }
612            other => panic!("Expected a Contender but found {:?}", other),
613        }
614    }
615
616    fn assert_examined_matched_contender(result: ExamineEventResult) {
617        match result {
618            ExamineEventResult::MatchedContender(boxed) => {
619                assert_eq!((&*boxed).as_any().type_id(), TypeId::of::<MatchedContender>());
620            }
621            other => panic!("Expected a MatchedContender but found {:?}", other),
622        }
623    }
624
625    fn assert_verified_matched_contender(result: VerifyEventResult) {
626        match result {
627            VerifyEventResult::MatchedContender(boxed) => {
628                assert_eq!((&*boxed).as_any().type_id(), TypeId::of::<MatchedContender>());
629            }
630            other => panic!("Expected a MatchedContender but found {:?}", other),
631        }
632    }
633
634    /// Tests that an InitialContender with a single touch contact and one
635    /// pressed button yields a Mismatch.
636    #[fuchsia::test]
637    fn contender_single_button() {
638        assert_matches!(
639            get_initial_contender().examine_event(&TouchpadEvent {
640                contacts: vec![create_touch_contact(0, Position::zero())],
641                timestamp: zx::MonotonicInstant::from_nanos(0),
642                pressed_buttons: vec![0],
643                filtered_palm_contacts: vec![],
644            },),
645            ExamineEventResult::Mismatch(_)
646        );
647    }
648
649    /// Tests that an InitialContender with a single touch contact and multiple
650    /// pressed button yields a Mismatch.
651    #[fuchsia::test]
652    fn contender_many_buttons() {
653        assert_matches!(
654            get_initial_contender().examine_event(&TouchpadEvent {
655                contacts: vec![create_touch_contact(0, Position::zero())],
656                timestamp: zx::MonotonicInstant::from_nanos(0),
657                pressed_buttons: vec![0, 1],
658                filtered_palm_contacts: vec![],
659            },),
660            ExamineEventResult::Mismatch(_)
661        );
662    }
663
664    /// Tests that an InitialContender with zero touch contacts yields a
665    /// Mismatch.
666    #[fuchsia::test]
667    fn contender_no_contacts() {
668        assert_matches!(
669            get_initial_contender().examine_event(&TouchpadEvent {
670                contacts: vec![],
671                timestamp: zx::MonotonicInstant::from_nanos(0),
672                pressed_buttons: vec![],
673                filtered_palm_contacts: vec![],
674            }),
675            ExamineEventResult::Mismatch(_)
676        );
677    }
678
679    /// Tests that an InitialContender with a single touch contact and no
680    /// pressed buttons yields a OneFingerContactContender.
681    #[fuchsia::test]
682    fn contender_one_contact() {
683        assert_contender(
684            get_initial_contender().examine_event(&TouchpadEvent {
685                contacts: vec![create_touch_contact(0, Position::zero())],
686                timestamp: zx::MonotonicInstant::from_nanos(0),
687                pressed_buttons: vec![],
688                filtered_palm_contacts: vec![],
689            }),
690            TypeId::of::<OneFingerContactContender>(),
691        );
692    }
693
694    /// Tests that an InitialContender with two touch contacts and no pressed
695    /// buttons yields a TwoFingerContactsContender.
696    #[fuchsia::test]
697    fn contender_two_contacts() {
698        assert_contender(
699            get_initial_contender().examine_event(&TouchpadEvent {
700                contacts: vec![
701                    create_touch_contact(0, Position::zero()),
702                    create_touch_contact(1, Position::zero()),
703                ],
704                timestamp: zx::MonotonicInstant::from_nanos(0),
705                pressed_buttons: vec![],
706                filtered_palm_contacts: vec![],
707            }),
708            TypeId::of::<TwoFingerContactsContender>(),
709        );
710    }
711
712    /// Tests that an InitialContender with more than two touch contacts yields
713    /// a Mismatch.
714    #[fuchsia::test]
715    fn contender_many_contacts() {
716        assert_matches!(
717            get_initial_contender().examine_event(&TouchpadEvent {
718                contacts: vec![
719                    create_touch_contact(0, Position::zero()),
720                    create_touch_contact(1, Position::zero()),
721                    create_touch_contact(2, Position::zero())
722                ],
723                timestamp: zx::MonotonicInstant::from_nanos(0),
724                pressed_buttons: vec![],
725                filtered_palm_contacts: vec![],
726            }),
727            ExamineEventResult::Mismatch(_)
728        );
729    }
730
731    /// Tests that a OneFingerContactContender with an event whose timestamp
732    /// exceeds the elapsed threshold yields a Mismatch.
733    #[fuchsia::test]
734    fn one_finger_contact_contender_too_long() {
735        assert_matches!(
736            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
737                contacts: vec![create_touch_contact(0, Position::zero()),],
738                timestamp: MAX_TIME_ELAPSED + zx::MonotonicInstant::from_nanos(1),
739                pressed_buttons: vec![],
740                filtered_palm_contacts: vec![],
741            }),
742            ExamineEventResult::Mismatch(_)
743        );
744    }
745
746    /// Tests that a OneFingerContactContender with one pressed button yields a
747    /// Mismatch.
748    #[fuchsia::test]
749    fn one_finger_contact_contender_single_button() {
750        assert_matches!(
751            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
752                contacts: vec![create_touch_contact(0, Position::zero())],
753                timestamp: zx::MonotonicInstant::from_nanos(0),
754                pressed_buttons: vec![0],
755                filtered_palm_contacts: vec![],
756            }),
757            ExamineEventResult::Mismatch(_)
758        );
759    }
760
761    /// Tests that a OneFingerContactContender with multiple pressed buttons
762    /// yields a Mismatch.
763    #[fuchsia::test]
764    fn one_finger_contact_contender_many_buttons() {
765        assert_matches!(
766            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
767                contacts: vec![create_touch_contact(0, Position::zero())],
768                timestamp: zx::MonotonicInstant::from_nanos(0),
769                pressed_buttons: vec![0, 1],
770                filtered_palm_contacts: vec![],
771            }),
772            ExamineEventResult::Mismatch(_)
773        );
774    }
775
776    /// Tests that a OneFingerContactContender with zero touch contacts yields a
777    /// Mismatch.
778    #[fuchsia::test]
779    fn one_finger_contact_contender_no_contacts() {
780        assert_matches!(
781            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
782                contacts: vec![],
783                timestamp: zx::MonotonicInstant::from_nanos(0),
784                pressed_buttons: vec![],
785                filtered_palm_contacts: vec![],
786            }),
787            ExamineEventResult::Mismatch(_)
788        );
789    }
790
791    /// Tests that a OneFingerContactContender with more than two touch contacts
792    /// yields a Mismatch.
793    #[fuchsia::test]
794    fn one_finger_contact_contender_many_touch_contacts() {
795        assert_matches!(
796            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
797                contacts: vec![
798                    create_touch_contact(0, Position::zero()),
799                    create_touch_contact(1, Position::zero()),
800                    create_touch_contact(2, Position::zero())
801                ],
802                timestamp: zx::MonotonicInstant::from_nanos(0),
803                pressed_buttons: vec![],
804                filtered_palm_contacts: vec![],
805            }),
806            ExamineEventResult::Mismatch(_)
807        );
808    }
809
810    /// Tests that a OneFingerContactContender with one touch contact yields
811    /// a OneFingerContactContender.
812    #[fuchsia::test]
813    fn one_finger_contact_contender_one_contact() {
814        assert_contender(
815            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
816                contacts: vec![create_touch_contact(0, Position::zero())],
817                timestamp: zx::MonotonicInstant::from_nanos(0),
818                pressed_buttons: vec![],
819                filtered_palm_contacts: vec![],
820            }),
821            TypeId::of::<OneFingerContactContender>(),
822        );
823    }
824
825    /// Tests that a OneFingerContactContender with two touch contacts yields
826    /// a TwoFingerContactsContender.
827    #[fuchsia::test]
828    fn one_finger_contact_contender_two_touch_contacts() {
829        assert_contender(
830            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
831                contacts: vec![
832                    create_touch_contact(0, Position::zero()),
833                    create_touch_contact(1, Position::zero()),
834                ],
835                timestamp: zx::MonotonicInstant::from_nanos(0),
836                pressed_buttons: vec![],
837                filtered_palm_contacts: vec![],
838            }),
839            TypeId::of::<TwoFingerContactsContender>(),
840        );
841    }
842
843    /// Tests that a OneFingerContactContender with a single touch contact and
844    /// too much displacement yields a Mismatch.
845    #[fuchsia::test]
846    fn one_finger_contact_contender_one_contact_large_displacement() {
847        assert_matches!(
848            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
849                contacts: vec![create_touch_contact(
850                    0,
851                    Position { x: MAX_FINGER_DISPLACEMENT_IN_MM, y: MAX_FINGER_DISPLACEMENT_IN_MM }
852                )],
853                timestamp: zx::MonotonicInstant::from_nanos(0),
854                pressed_buttons: vec![],
855                filtered_palm_contacts: vec![],
856            }),
857            ExamineEventResult::Mismatch(_)
858        );
859    }
860
861    /// Tests that a OneFingerContactContender with two touch contacts and
862    /// one with too much displacement yields a Mismatch.
863    #[fuchsia::test]
864    fn one_finger_contact_contender_two_contacts_large_displacement() {
865        assert_matches!(
866            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
867                contacts: vec![
868                    create_touch_contact(
869                        0,
870                        Position {
871                            x: MAX_FINGER_DISPLACEMENT_IN_MM,
872                            y: MAX_FINGER_DISPLACEMENT_IN_MM
873                        }
874                    ),
875                    create_touch_contact(1, Position::zero())
876                ],
877                timestamp: zx::MonotonicInstant::from_nanos(0),
878                pressed_buttons: vec![],
879                filtered_palm_contacts: vec![],
880            }),
881            ExamineEventResult::Mismatch(_)
882        );
883    }
884
885    /// Tests that a OneFingerContactContender with a single touch contact
886    /// and acceptable displacement yields a OneFingerContactContender.
887    #[fuchsia::test]
888    fn one_finger_contact_contender_one_contact_some_displacement() {
889        assert_contender(
890            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
891                contacts: vec![create_touch_contact(
892                    0,
893                    Position { x: HALF_MOTION, y: HALF_MOTION },
894                )],
895                timestamp: zx::MonotonicInstant::from_nanos(0),
896                pressed_buttons: vec![],
897                filtered_palm_contacts: vec![],
898            }),
899            TypeId::of::<OneFingerContactContender>(),
900        );
901    }
902
903    /// Tests that a OneFingerContactContender with a two touch contacts
904    /// and one with acceptable displacement yields a OneFingerContactContender.
905    #[fuchsia::test]
906    fn one_finger_contact_contender_two_contacts_some_displacement() {
907        assert_contender(
908            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
909                contacts: vec![
910                    create_touch_contact(0, Position { x: HALF_MOTION, y: HALF_MOTION }),
911                    create_touch_contact(1, Position::zero()),
912                ],
913                timestamp: zx::MonotonicInstant::from_nanos(0),
914                pressed_buttons: vec![],
915                filtered_palm_contacts: vec![],
916            }),
917            TypeId::of::<TwoFingerContactsContender>(),
918        );
919    }
920
921    /// Tests that a TwoFingerContactsContender with an event whose timestamp
922    /// exceeds the elapsed threshold yields a Mismatch.
923    #[fuchsia::test]
924    fn two_finger_contacts_contender_too_long() {
925        assert_matches!(
926            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
927                contacts: vec![],
928                timestamp: MAX_TIME_ELAPSED + zx::MonotonicInstant::from_nanos(1),
929                pressed_buttons: vec![],
930                filtered_palm_contacts: vec![],
931            }),
932            ExamineEventResult::Mismatch(_)
933        );
934    }
935
936    /// Tests that a TwoFingerContactsContender with one pressed button yields a
937    /// Mismatch.
938    #[fuchsia::test]
939    fn two_finger_contacts_contender_single_button() {
940        assert_matches!(
941            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
942                contacts: vec![],
943                timestamp: zx::MonotonicInstant::from_nanos(0),
944                pressed_buttons: vec![0],
945                filtered_palm_contacts: vec![],
946            }),
947            ExamineEventResult::Mismatch(_)
948        );
949    }
950
951    /// Tests that a TwoFingerContactsContender with multiple pressed buttons
952    /// yields a Mismatch.
953    #[fuchsia::test]
954    fn two_finger_contacts_contender_many_buttons() {
955        assert_matches!(
956            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
957                contacts: vec![],
958                timestamp: zx::MonotonicInstant::from_nanos(0),
959                pressed_buttons: vec![0, 1],
960                filtered_palm_contacts: vec![],
961            }),
962            ExamineEventResult::Mismatch(_)
963        );
964    }
965
966    /// Tests that a TwoFingerContactsContender with zero touch contacts yields a
967    /// MatchedContender.
968    #[fuchsia::test]
969    fn two_finger_contacts_contender_no_touch_contacts() {
970        assert_examined_matched_contender(get_two_finger_contacts_contender().examine_event(
971            &TouchpadEvent {
972                contacts: vec![],
973                timestamp: zx::MonotonicInstant::from_nanos(0),
974                pressed_buttons: vec![],
975                filtered_palm_contacts: vec![],
976            },
977        ));
978    }
979
980    /// Tests that a TwoFingerContactsContender with one touch contact with
981    /// acceptable displacement yields a OneFingerRaisedContender.
982    #[fuchsia::test]
983    fn two_finger_contacts_contender_one_contact() {
984        assert_contender(
985            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
986                contacts: vec![create_touch_contact(0, Position::zero())],
987                timestamp: zx::MonotonicInstant::from_nanos(0),
988                pressed_buttons: vec![],
989                filtered_palm_contacts: vec![],
990            }),
991            TypeId::of::<OneFingerRaisedContender>(),
992        );
993    }
994
995    /// Tests that a TwoFingerContactsContender with one touch contact with
996    /// too much displacement yields a Mismatch.
997    #[fuchsia::test]
998    fn two_finger_contacts_contender_one_contact_large_displacement() {
999        assert_matches!(
1000            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1001                contacts: vec![create_touch_contact(
1002                    0,
1003                    Position { x: MAX_FINGER_DISPLACEMENT_IN_MM, y: MAX_FINGER_DISPLACEMENT_IN_MM },
1004                )],
1005                timestamp: zx::MonotonicInstant::from_nanos(0),
1006                pressed_buttons: vec![],
1007                filtered_palm_contacts: vec![],
1008            }),
1009            ExamineEventResult::Mismatch(_)
1010        );
1011    }
1012
1013    /// Tests that a TwoFingerContactsContender with more than two touch contacts
1014    /// yields a Mismatch.
1015    #[fuchsia::test]
1016    fn two_finger_contacts_contender_many_touch_contacts() {
1017        assert_matches!(
1018            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1019                contacts: vec![
1020                    create_touch_contact(0, Position::zero()),
1021                    create_touch_contact(1, Position::zero()),
1022                    create_touch_contact(2, Position::zero())
1023                ],
1024                timestamp: zx::MonotonicInstant::from_nanos(0),
1025                pressed_buttons: vec![],
1026                filtered_palm_contacts: vec![],
1027            }),
1028            ExamineEventResult::Mismatch(_)
1029        );
1030    }
1031
1032    /// Tests that a TwoFingerContactsContender with two touch contacts yields
1033    /// a TwoFingerContactsContender.
1034    #[fuchsia::test]
1035    fn two_finger_contacts_contender_two_touch_contacts() {
1036        assert_contender(
1037            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1038                contacts: vec![
1039                    create_touch_contact(0, Position::zero()),
1040                    create_touch_contact(1, Position::zero()),
1041                ],
1042                timestamp: zx::MonotonicInstant::from_nanos(0),
1043                pressed_buttons: vec![],
1044                filtered_palm_contacts: vec![],
1045            }),
1046            TypeId::of::<TwoFingerContactsContender>(),
1047        );
1048    }
1049
1050    /// Tests that a TwoFingerContactsContender with two touch contacts and
1051    /// one with too much displacement yields a Mismatch.
1052    #[fuchsia::test]
1053    fn two_finger_contacts_contender_two_contacts_large_displacement() {
1054        assert_matches!(
1055            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1056                contacts: vec![
1057                    create_touch_contact(
1058                        0,
1059                        Position {
1060                            x: MAX_FINGER_DISPLACEMENT_IN_MM,
1061                            y: MAX_FINGER_DISPLACEMENT_IN_MM
1062                        }
1063                    ),
1064                    create_touch_contact(1, Position::zero())
1065                ],
1066                timestamp: zx::MonotonicInstant::from_nanos(0),
1067                pressed_buttons: vec![],
1068                filtered_palm_contacts: vec![],
1069            }),
1070            ExamineEventResult::Mismatch(_)
1071        );
1072
1073        assert_matches!(
1074            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1075                contacts: vec![
1076                    create_touch_contact(0, Position::zero()),
1077                    create_touch_contact(
1078                        1,
1079                        Position {
1080                            x: MAX_FINGER_DISPLACEMENT_IN_MM,
1081                            y: MAX_FINGER_DISPLACEMENT_IN_MM
1082                        }
1083                    ),
1084                ],
1085                timestamp: zx::MonotonicInstant::from_nanos(0),
1086                pressed_buttons: vec![],
1087                filtered_palm_contacts: vec![],
1088            }),
1089            ExamineEventResult::Mismatch(_)
1090        );
1091    }
1092
1093    /// Tests that a TwoFingerContactsContender with two touch contact
1094    /// and acceptable displacement yields a TwoFingerContactsContender.
1095    #[fuchsia::test]
1096    fn two_finger_contacts_contender_two_contacts_some_displacement() {
1097        assert_contender(
1098            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1099                contacts: vec![
1100                    create_touch_contact(0, Position::zero()),
1101                    create_touch_contact(1, Position { x: HALF_MOTION, y: HALF_MOTION }),
1102                ],
1103                timestamp: zx::MonotonicInstant::from_nanos(0),
1104                pressed_buttons: vec![],
1105                filtered_palm_contacts: vec![],
1106            }),
1107            TypeId::of::<TwoFingerContactsContender>(),
1108        );
1109
1110        assert_contender(
1111            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1112                contacts: vec![
1113                    create_touch_contact(0, Position { x: HALF_MOTION, y: HALF_MOTION }),
1114                    create_touch_contact(1, Position::zero()),
1115                ],
1116                timestamp: zx::MonotonicInstant::from_nanos(0),
1117                pressed_buttons: vec![],
1118                filtered_palm_contacts: vec![],
1119            }),
1120            TypeId::of::<TwoFingerContactsContender>(),
1121        );
1122
1123        assert_contender(
1124            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1125                contacts: vec![
1126                    create_touch_contact(0, Position { x: HALF_MOTION, y: HALF_MOTION }),
1127                    create_touch_contact(1, Position { x: HALF_MOTION, y: HALF_MOTION }),
1128                ],
1129                timestamp: zx::MonotonicInstant::from_nanos(0),
1130                pressed_buttons: vec![],
1131                filtered_palm_contacts: vec![],
1132            }),
1133            TypeId::of::<TwoFingerContactsContender>(),
1134        );
1135    }
1136
1137    /// Tests that a OneFingerRaisedContender with an event whose timestamp
1138    /// exceeds the elapsed threshold yields a Mismatch.
1139    #[fuchsia::test]
1140    fn one_finger_raised_contender_too_long() {
1141        assert_matches!(
1142            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1143                contacts: vec![],
1144                timestamp: MAX_TIME_ELAPSED + zx::MonotonicInstant::from_nanos(1),
1145                pressed_buttons: vec![],
1146                filtered_palm_contacts: vec![],
1147            }),
1148            ExamineEventResult::Mismatch(_)
1149        );
1150    }
1151
1152    /// Tests that a OneFingerRaisedContender with one pressed button yields a
1153    /// Mismatch.
1154    #[fuchsia::test]
1155    fn one_finger_raised_contender_single_button() {
1156        assert_matches!(
1157            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1158                contacts: vec![],
1159                timestamp: zx::MonotonicInstant::from_nanos(0),
1160                pressed_buttons: vec![0],
1161                filtered_palm_contacts: vec![],
1162            }),
1163            ExamineEventResult::Mismatch(_)
1164        );
1165    }
1166
1167    /// Tests that a OneFingerRaisedContender with multiple pressed buttons
1168    /// yields a Mismatch.
1169    #[fuchsia::test]
1170    fn one_finger_raised_contender_many_buttons() {
1171        assert_matches!(
1172            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1173                contacts: vec![],
1174                timestamp: zx::MonotonicInstant::from_nanos(0),
1175                pressed_buttons: vec![0, 1],
1176                filtered_palm_contacts: vec![],
1177            }),
1178            ExamineEventResult::Mismatch(_)
1179        );
1180    }
1181
1182    /// Tests that a OneFingerRaisedContender with zero touch contacts yields a
1183    /// MatchedContender.
1184    #[fuchsia::test]
1185    fn one_finger_raised_contender_no_touch_contacts() {
1186        assert_examined_matched_contender(get_one_finger_raised_contender().examine_event(
1187            &TouchpadEvent {
1188                contacts: vec![],
1189                timestamp: zx::MonotonicInstant::from_nanos(0),
1190                pressed_buttons: vec![],
1191                filtered_palm_contacts: vec![],
1192            },
1193        ));
1194    }
1195
1196    /// Tests that a OneFingerRaisedContender with one touch contact with
1197    /// acceptable displacement against first recorded contact yields a
1198    /// OneFingerRaisedContender.
1199    #[fuchsia::test]
1200    fn one_finger_raised_contender_one_contact_first_id() {
1201        assert_contender(
1202            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1203                contacts: vec![create_touch_contact(0, Position::zero())],
1204                timestamp: zx::MonotonicInstant::from_nanos(0),
1205                pressed_buttons: vec![],
1206                filtered_palm_contacts: vec![],
1207            }),
1208            TypeId::of::<OneFingerRaisedContender>(),
1209        );
1210
1211        assert_contender(
1212            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1213                contacts: vec![create_touch_contact(
1214                    0,
1215                    Position { x: HALF_MOTION, y: HALF_MOTION },
1216                )],
1217                timestamp: zx::MonotonicInstant::from_nanos(0),
1218                pressed_buttons: vec![],
1219                filtered_palm_contacts: vec![],
1220            }),
1221            TypeId::of::<OneFingerRaisedContender>(),
1222        );
1223    }
1224
1225    /// Tests that a OneFingerRaisedContender with one touch contact with
1226    /// acceptable displacement against second recorded contact yields a
1227    /// OneFingerRaisedContender.
1228    #[fuchsia::test]
1229    fn one_finger_raised_contender_one_contact_second_id() {
1230        assert_contender(
1231            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1232                contacts: vec![create_touch_contact(1, Position::zero())],
1233                timestamp: zx::MonotonicInstant::from_nanos(0),
1234                pressed_buttons: vec![],
1235                filtered_palm_contacts: vec![],
1236            }),
1237            TypeId::of::<OneFingerRaisedContender>(),
1238        );
1239
1240        assert_contender(
1241            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1242                contacts: vec![create_touch_contact(
1243                    1,
1244                    Position { x: HALF_MOTION, y: HALF_MOTION },
1245                )],
1246                timestamp: zx::MonotonicInstant::from_nanos(0),
1247                pressed_buttons: vec![],
1248                filtered_palm_contacts: vec![],
1249            }),
1250            TypeId::of::<OneFingerRaisedContender>(),
1251        );
1252    }
1253
1254    /// Tests that a OneFingerRaisedContender with one touch contact with
1255    /// acceptable displacement against an unrecorded contact id yields a
1256    /// Mismatch.
1257    #[fuchsia::test]
1258    fn one_finger_raised_contender_one_contact_invalid_id() {
1259        assert_matches!(
1260            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1261                contacts: vec![create_touch_contact(2, Position::zero(),)],
1262                timestamp: zx::MonotonicInstant::from_nanos(0),
1263                pressed_buttons: vec![],
1264                filtered_palm_contacts: vec![],
1265            }),
1266            ExamineEventResult::Mismatch(_)
1267        );
1268    }
1269
1270    /// Tests that a OneFingerRaisedContender with one touch contact with
1271    /// too much displacement yields a Mismatch.
1272    #[fuchsia::test]
1273    fn one_finger_raised_contender_one_contact_large_displacement() {
1274        assert_matches!(
1275            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1276                contacts: vec![create_touch_contact(
1277                    0,
1278                    Position { x: MAX_FINGER_DISPLACEMENT_IN_MM, y: MAX_FINGER_DISPLACEMENT_IN_MM },
1279                )],
1280                timestamp: zx::MonotonicInstant::from_nanos(0),
1281                pressed_buttons: vec![],
1282                filtered_palm_contacts: vec![],
1283            }),
1284            ExamineEventResult::Mismatch(_)
1285        );
1286    }
1287
1288    /// Tests that a OneFingerRaisedContender with more than one touch contacts
1289    /// yields a Mismatch.
1290    #[fuchsia::test]
1291    fn one_finger_raised_contender_many_touch_contacts() {
1292        assert_matches!(
1293            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1294                contacts: vec![
1295                    create_touch_contact(0, Position::zero()),
1296                    create_touch_contact(1, Position::zero()),
1297                ],
1298                timestamp: zx::MonotonicInstant::from_nanos(0),
1299                pressed_buttons: vec![],
1300                filtered_palm_contacts: vec![],
1301            }),
1302            ExamineEventResult::Mismatch(_)
1303        );
1304    }
1305
1306    /// Tests that a MatchedContender with an event whose timestamp exceeds
1307    /// the elapsed threshold yields a Mismatch.
1308    #[fuchsia::test]
1309    fn matched_contender_too_long() {
1310        assert_matches!(
1311            get_matched_contender().verify_event(&TouchpadEvent {
1312                contacts: vec![],
1313                timestamp: MAX_TIME_ELAPSED + zx::MonotonicInstant::from_nanos(1),
1314                pressed_buttons: vec![],
1315                filtered_palm_contacts: vec![],
1316            }),
1317            VerifyEventResult::Mismatch(_)
1318        );
1319    }
1320
1321    /// Tests that a MatchedContender with one touch contact yields a Mismatch.
1322    #[fuchsia::test]
1323    fn matched_contender_one_contact() {
1324        assert_matches!(
1325            get_matched_contender().verify_event(&TouchpadEvent {
1326                contacts: vec![create_touch_contact(0, Position::zero())],
1327                timestamp: zx::MonotonicInstant::from_nanos(0),
1328                pressed_buttons: vec![],
1329                filtered_palm_contacts: vec![],
1330            }),
1331            VerifyEventResult::Mismatch(_)
1332        );
1333    }
1334
1335    /// Tests that a MatchedContender with multiple touch contacts yields a
1336    /// Mismatch.
1337    #[fuchsia::test]
1338    fn matched_contender_many_contacts() {
1339        assert_matches!(
1340            get_matched_contender().verify_event(&TouchpadEvent {
1341                contacts: vec![
1342                    create_touch_contact(0, Position::zero()),
1343                    create_touch_contact(1, Position::zero())
1344                ],
1345                timestamp: zx::MonotonicInstant::from_nanos(0),
1346                pressed_buttons: vec![],
1347                filtered_palm_contacts: vec![],
1348            }),
1349            VerifyEventResult::Mismatch(_)
1350        );
1351    }
1352
1353    /// Tests that a MatchedContender with one button pressed yields a Mismatch.
1354    #[fuchsia::test]
1355    fn matched_contender_one_button() {
1356        assert_matches!(
1357            get_matched_contender().verify_event(&TouchpadEvent {
1358                contacts: vec![],
1359                timestamp: zx::MonotonicInstant::from_nanos(0),
1360                pressed_buttons: vec![0],
1361                filtered_palm_contacts: vec![],
1362            }),
1363            VerifyEventResult::Mismatch(_)
1364        );
1365    }
1366
1367    /// Tests that a MatchedContender with multiple buttons pressed yields a
1368    /// Mismatch.
1369    #[fuchsia::test]
1370    fn matched_contender_many_buttons() {
1371        assert_matches!(
1372            get_matched_contender().verify_event(&TouchpadEvent {
1373                contacts: vec![],
1374                timestamp: zx::MonotonicInstant::from_nanos(0),
1375                pressed_buttons: vec![0, 1],
1376                filtered_palm_contacts: vec![],
1377            }),
1378            VerifyEventResult::Mismatch(_)
1379        );
1380    }
1381
1382    /// Tests that a MatchedContender with no touch contacts yields a
1383    /// MatchedContender.
1384    #[fuchsia::test]
1385    fn matched_contender_no_contacts() {
1386        assert_verified_matched_contender(get_matched_contender().verify_event(&TouchpadEvent {
1387            contacts: vec![],
1388            timestamp: zx::MonotonicInstant::from_nanos(0),
1389            pressed_buttons: vec![],
1390            filtered_palm_contacts: vec![],
1391        }));
1392    }
1393
1394    /// Tests that a MatchedContender processes buffered events by
1395    /// returning mouse down and mouse up events.
1396    #[fuchsia::test]
1397    fn matched_contender_process_buffered_events() {
1398        let ProcessBufferedEventsResult { generated_events, winner, recognized_gesture } =
1399            get_matched_contender().process_buffered_events(vec![]);
1400
1401        assert_eq!(
1402            generated_events,
1403            [
1404                gesture_arena::MouseEvent {
1405                    timestamp: zx::MonotonicInstant::from_nanos(0),
1406                    mouse_data: MouseEvent {
1407                        location: MouseLocation::Relative(RelativeLocation {
1408                            millimeters: Position { x: 0.0, y: 0.0 }
1409                        }),
1410                        wheel_delta_v: None,
1411                        wheel_delta_h: None,
1412                        phase: MousePhase::Down,
1413                        affected_buttons: hashset! {SECONDARY_BUTTON},
1414                        pressed_buttons: hashset! {SECONDARY_BUTTON},
1415                        is_precision_scroll: None,
1416                        wake_lease: Mutex::new(None),
1417                    },
1418                },
1419                gesture_arena::MouseEvent {
1420                    timestamp: zx::MonotonicInstant::from_nanos(123),
1421                    mouse_data: MouseEvent {
1422                        location: MouseLocation::Relative(RelativeLocation {
1423                            millimeters: Position { x: 0.0, y: 0.0 }
1424                        }),
1425                        wheel_delta_v: None,
1426                        wheel_delta_h: None,
1427                        phase: MousePhase::Up,
1428                        affected_buttons: hashset! {SECONDARY_BUTTON},
1429                        pressed_buttons: hashset! {},
1430                        is_precision_scroll: None,
1431                        wake_lease: Mutex::new(None),
1432                    },
1433                }
1434            ]
1435        );
1436        assert_matches!(winner, None);
1437        assert_eq!(recognized_gesture, RecognizedGesture::SecondaryTap);
1438    }
1439}