1dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang# Use of this source code is governed by a BSD-style license that can be
3dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang# found in the LICENSE file.
4dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang#
5dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
6dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang"""This module contains unit tests for the classes in the validators module."""
7dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
8efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwangimport glob
9dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwangimport os.path
10dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwangimport unittest
11dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
12dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwangimport common_unittest_utils
13dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwangimport common_util
14dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwangimport test_conf as conf
1510016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwangimport validators
16dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
17f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwangfrom common_unittest_utils import create_mocked_devices, parse_tests_data
182c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwangfrom firmware_constants import AXIS, GV, MTB, PLATFORM, VAL
19b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwangfrom firmware_log import MetricNameProps
20ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwangfrom geometry.elements import Point
213f245993196c7cead8716ff09633a6ad49e8b006Joseph Hwangfrom touch_device import TouchDevice
22dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwangfrom validators import (CountPacketsValidator,
23dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                        CountTrackingIDValidator,
24e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang                        DiscardInitialSecondsValidator,
25dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                        DrumrollValidator,
26a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang                        HysteresisValidator,
27dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                        LinearityValidator,
2860a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang                        MtbSanityValidator,
29dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                        NoGapValidator,
30cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang                        NoLevelJumpValidator,
31dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                        NoReversedMotionValidator,
32dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                        PhysicalClickValidator,
33dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                        PinchValidator,
34dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                        RangeValidator,
350d074428ab1b7cc71afd30ce1cfc863e13793fffCharlie Mooney                        ReportRateValidator,
36dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                        StationaryFingerValidator,
3787321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang                        StationaryTapValidator,
38dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang)
39dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
40dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
41efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwangunittest_path_lumpy = os.path.join(os.getcwd(), 'tests/logs/lumpy')
423f245993196c7cead8716ff09633a6ad49e8b006Joseph Hwangmocked_device = create_mocked_devices()
433f245993196c7cead8716ff09633a6ad49e8b006Joseph Hwang
44f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang# Make short aliases for supported platforms
45f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwangalex = mocked_device[PLATFORM.ALEX]
46f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwanglumpy = mocked_device[PLATFORM.LUMPY]
47f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwanglink = mocked_device[PLATFORM.LINK]
48f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang# Some tests do not care what device is used.
49f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwangdontcare = 'dontcare'
50f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang
513f245993196c7cead8716ff09633a6ad49e8b006Joseph Hwang
52e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwangclass CountTrackingIDValidatorTest(unittest.TestCase):
53dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    """Unit tests for CountTrackingIDValidator class."""
54dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
55dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def _test_count_tracking_id(self, filename, criteria, device):
56dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        packets = parse_tests_data(filename)
57dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        validator = CountTrackingIDValidator(criteria, device=device)
587981beea4b6dfdff43ca61e17b51ba295a342702Joseph Hwang        vlog = validator.check(packets)
59ecc254fc00e6b3504d4f7d87abad937cf73a267dJoseph Hwang        return vlog.score
60dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
61dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_two_finger_id_change(self):
62dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Two two fingers id change.
63dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
64dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue 7867: Cyapa : Two finger scroll, tracking ids change
65dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
66dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'two_finger_id_change.dat'
67f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score = self._test_count_tracking_id(filename, '== 2', lumpy)
68dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.assertTrue(score == 0)
69dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
70dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_one_finger_fast_swipe_id_split(self):
71dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """One finger fast swipe resulting in IDs split.
72dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
73dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue: 7869: Lumpy: Tracking ID reassigned during quick-2F-swipe
74dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
75dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'one_finger_fast_swipe_id_split.dat'
76f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score = self._test_count_tracking_id(filename, '== 1', lumpy)
77dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.assertTrue(score == 0)
78dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
79dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_two_fingers_fast_flick_id_split(self):
80dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Two figners fast flick resulting in IDs split.
81dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
82dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue: 7869: Lumpy: Tracking ID reassigned during quick-2F-swipe
83dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
84dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'two_finger_fast_flick_id_split.dat'
85f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score = self._test_count_tracking_id(filename, '== 2', lumpy)
86dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.assertTrue(score == 0)
87dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
88dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
89e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwangclass DrumrollValidatorTest(unittest.TestCase):
90dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    """Unit tests for DrumrollValidator class."""
91dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
92dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def setUp(self):
93dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.criteria = conf.drumroll_criteria
94dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
95dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def _test_drumroll(self, filename, criteria, device):
96dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        packets = parse_tests_data(filename)
97dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        validator = DrumrollValidator(criteria, device=device)
987981beea4b6dfdff43ca61e17b51ba295a342702Joseph Hwang        vlog = validator.check(packets)
99ecc254fc00e6b3504d4f7d87abad937cf73a267dJoseph Hwang        return vlog.score
100dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
101313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang    def _get_drumroll_metrics(self, filename, criteria, device):
102efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        packets = parse_tests_data(filename, gesture_dir=unittest_path_lumpy)
103313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang        validator = DrumrollValidator(criteria, device=device)
104313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang        metrics = validator.check(packets).metrics
105313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang        return metrics
106313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang
107dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_drumroll_lumpy(self):
108dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Should catch the drumroll on lumpy.
109dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
110dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue 7809: Lumpy: Drumroll bug in firmware
111edb699f26760c240b23230b450135470a8e44a34Joseph Hwang        Max distance: 52.02 px
112dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
113dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'drumroll_lumpy.dat'
114f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score = self._test_drumroll(filename, self.criteria, lumpy)
115dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.assertTrue(score == 0)
116dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
117dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_drumroll_lumpy_1(self):
118dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Should catch the drumroll on lumpy.
119dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
120dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue 7809: Lumpy: Drumroll bug in firmware
121edb699f26760c240b23230b450135470a8e44a34Joseph Hwang        Max distance: 43.57 px
122dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
123dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'drumroll_lumpy_1.dat'
124f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score = self._test_drumroll(filename, self.criteria, lumpy)
125edb699f26760c240b23230b450135470a8e44a34Joseph Hwang        self.assertTrue(score <= 0.15)
126dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
127dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_no_drumroll_link(self):
128dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Should pass (score == 1) when there is no drumroll.
129dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
130dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue 7809: Lumpy: Drumroll bug in firmware
131edb699f26760c240b23230b450135470a8e44a34Joseph Hwang        Max distance: 2.92 px
132dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
133dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'no_drumroll_link.dat'
134f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score = self._test_drumroll(filename, self.criteria, link)
135dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.assertTrue(score == 1)
136dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
137313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang    def test_drumroll_metrics(self):
138313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang        """Test the drumroll metrics."""
139313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang        expected_max_values = {
140313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            '20130506_030025-fw_11.27-robot_sim/'
141313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            'drumroll.fast-lumpy-fw_11.27-manual-20130528_044804.dat':
142313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            2.29402908535,
143313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang
144313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            '20130506_030025-fw_11.27-robot_sim/'
145313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            'drumroll.fast-lumpy-fw_11.27-manual-20130528_044820.dat':
146313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            0.719567771497,
147313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang
148313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            '20130506_031746-fw_11.27-robot_sim/'
149313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            'drumroll.fast-lumpy-fw_11.27-manual-20130528_044728.dat':
150313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            0.833491481592,
151313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang
152313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            '20130506_032458-fw_11.23-robot_sim/'
153313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            'drumroll.fast-lumpy-fw_11.23-manual-20130528_044856.dat':
154313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            1.18368539364,
155313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang
156313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            '20130506_032458-fw_11.23-robot_sim/'
157313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            'drumroll.fast-lumpy-fw_11.23-manual-20130528_044907.dat':
158313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            0.851161282019,
159313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang
160313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            '20130506_032659-fw_11.23-robot_sim/'
161313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            'drumroll.fast-lumpy-fw_11.23-manual-20130528_044933.dat':
162313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            2.64245519251,
163313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang
164313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            '20130506_032659-fw_11.23-robot_sim/'
165313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            'drumroll.fast-lumpy-fw_11.23-manual-20130528_044947.dat':
166313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            0.910624022916,
167313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang        }
168313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang        criteria = self.criteria
169313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang        for filename, expected_max_value in expected_max_values.items():
170f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang            metrics = self._get_drumroll_metrics(filename, criteria, lumpy)
171313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            actual_max_value = max([m.value for m in metrics])
172313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang            self.assertAlmostEqual(expected_max_value, actual_max_value)
173313de5edc48d6af3b8891e69114ddf7d79c8516cJoseph Hwang
174dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
175e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwangclass LinearityValidatorTest(unittest.TestCase):
176dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    """Unit tests for LinearityValidator class."""
177dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
178dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def setUp(self):
17910016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        self.validator = LinearityValidator(conf.linearity_criteria,
180907efec59a199502d5508af023cd0668dcaffa1aJoseph Hwang                                            device=lumpy, finger=0)
18110016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        self.validator.init_check()
18210016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang
18310016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang    def test_simple_linear_regression0(self):
18410016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        """A perfect y-t line from bottom left to top right"""
18510016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        list_y = [20, 40, 60, 80, 100, 120, 140, 160]
18610016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        list_t = [i * 0.1 for i in range(len(list_y))]
18710016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        (max_err_px, rms_err_px) = self.validator._calc_errors_single_axis(
18810016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang                list_t, list_y)
18910016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        self.assertAlmostEqual(max_err_px, 0)
19010016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        self.assertAlmostEqual(rms_err_px, 0)
19110016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang
192eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang    def test_simple_linear_regression0b(self):
193eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        """An imperfect y-t line from bottom left to top right with
194eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        the first and the last entries as outliers.
195eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang
196eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        In this test case:
197eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang          begin segment = [1,]
198eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang          end segment = [188, 190]
199eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang          middle segment = [20, 40, 60, 80, 100, 120, 140, 160]
200eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang
201eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang          the simple linear regression line is calculated based on the
202eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang          middle segment, and is
203eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            y = 20 * t
204eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang          the error = [1, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10]
205eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        """
206eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        list_y = [1, 20, 40, 60, 80, 100, 120, 140, 160, 188, 190]
207eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        list_t = range(len(list_y))
208eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang
209eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        expected_errs_dict = {
210eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            VAL.WHOLE: [1, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10],
211eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            VAL.BEGIN: [1, ],
212eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            VAL.END: [8, 10],
213eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            VAL.BOTH_ENDS: [1, 8, 10],
214eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        }
215eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang
216eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        for segment_flag, expected_errs in expected_errs_dict.items():
217eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            self.validator._segments= segment_flag
218eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            (max_err, rms_err) = self.validator._calc_errors_single_axis(list_t,
219eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang                                                                         list_y)
220eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            expected_max_err = max(expected_errs)
221eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            expected_rms_err = (sum([i ** 2 for i in expected_errs]) /
222eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang                                len(expected_errs)) ** 0.5
223eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            self.assertAlmostEqual(max_err, expected_max_err)
224eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            self.assertAlmostEqual(rms_err, expected_rms_err)
225eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang
226eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang    def test_log_details_and_metrics(self):
227eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        """Test the axes in _log_details_and_metrics"""
228eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        # gesture_dir: tests/data/linearity
229eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        gesture_dir = 'linearity'
230eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        filenames_axes = {
231eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            'two_finger_tracking.right_to_left.slow-lumpy-fw_11.27-robot-'
232eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang                '20130227_204458.dat': [AXIS.X],
233eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            'one_finger_to_edge.center_to_top.slow-lumpy-fw_11.27-robot-'
234eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang                '20130227_203228.dat': [AXIS.Y],
235eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            'two_finger_tracking.bottom_left_to_top_right.normal-lumpy-'
236eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang                'fw_11.27-robot-20130227_204902.dat': [AXIS.X, AXIS.Y],
237eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        }
238eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang        for filename, expected_axes in filenames_axes.items():
239eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            packets = parse_tests_data(filename, gesture_dir=gesture_dir)
240eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            # get the direction of the gesture
241eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            direction = [filename.split('-')[0].split('.')[1]]
242eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            self.validator.check(packets, direction)
243eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            actual_axes = sorted(self.validator.list_coords.keys())
244eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang            self.assertEqual(actual_axes, expected_axes)
245eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang
246eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang    def _test_simple_linear_regression1(self):
24710016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        """A y-t line taken from a real example.
24810016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang
24910016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        Refer to the "Numerical example" in the wiki page:
25010016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang            http://en.wikipedia.org/wiki/Simple_linear_regression
25110016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        """
25210016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        list_t = [1.47, 1.50, 1.52, 1.55, 1.57, 1.60, 1.63, 1.65, 1.68, 1.70,
25310016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang                  1.73, 1.75, 1.78, 1.80, 1.83]
25410016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        list_y = [52.21, 53.12, 54.48, 55.84, 57.20, 58.57, 59.93, 61.29,
25510016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang                  63.11, 64.47, 66.28, 68.10, 69.92, 72.19, 74.46]
25610016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        expected_max_err = 1.3938545467809007
25710016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        expected_rms_err = 0.70666155991311708
25810016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        (max_err, rms_err) = self.validator._calc_errors_single_axis(
25910016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang                list_t, list_y)
26010016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        self.assertAlmostEqual(max_err, expected_max_err)
26110016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang        self.assertAlmostEqual(rms_err, expected_rms_err)
26210016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang
26310016f7a7ffb74c3c03ac548575ac74bd1a9a222Joseph Hwang
264e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwangclass NoGapValidatorTest(unittest.TestCase):
265dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    """Unit tests for NoGapValidator class."""
266a121b27b9145326852c5fe66e98df189c4b0fd90Joseph Hwang    GAPS_SUBDIR = 'gaps'
267dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
268dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def setUp(self):
269dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.criteria = conf.no_gap_criteria
270dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
271dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def _test_no_gap(self, filename, criteria, device, slot):
272a121b27b9145326852c5fe66e98df189c4b0fd90Joseph Hwang        file_subpath = os.path.join(self.GAPS_SUBDIR, filename)
273a121b27b9145326852c5fe66e98df189c4b0fd90Joseph Hwang        packets = parse_tests_data(file_subpath)
274dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        validator = NoGapValidator(criteria, device=device, slot=slot)
2757981beea4b6dfdff43ca61e17b51ba295a342702Joseph Hwang        vlog = validator.check(packets)
276ecc254fc00e6b3504d4f7d87abad937cf73a267dJoseph Hwang        return vlog.score
277dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
278dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_two_finger_scroll_gaps(self):
279dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Test that there are gaps in the two finger scroll gesture.
280dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
281dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue 7552: Cyapa : two finger scroll motion produces gaps in tracking
282dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
283dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'two_finger_gaps.horizontal.dat'
284f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score0 = self._test_no_gap(filename, self.criteria, lumpy, 0)
285f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score1 = self._test_no_gap(filename, self.criteria, lumpy, 1)
286dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.assertTrue(score0 <= 0.1)
287dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.assertTrue(score1 <= 0.1)
288dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
289dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_gap_new_finger_arriving_or_departing(self):
290dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Test gap when new finger arriving or departing.
291dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
292dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue: 8005: Cyapa : gaps appear when new finger arrives or departs
293dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
294dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'gap_new_finger_arriving_or_departing.dat'
295f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score = self._test_no_gap(filename, self.criteria, lumpy, 0)
296a121b27b9145326852c5fe66e98df189c4b0fd90Joseph Hwang        self.assertTrue(score <= 0.3)
297dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
298dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_one_stationary_finger_2nd_finger_moving_gaps(self):
299dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Test one stationary finger resulting in 2nd finger moving gaps."""
300dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'one_stationary_finger_2nd_finger_moving_gaps.dat'
301f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score = self._test_no_gap(filename, self.criteria, lumpy, 1)
302dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        self.assertTrue(score <= 0.1)
303dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
304dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_resting_finger_2nd_finger_moving_gaps(self):
305dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Test resting finger resulting in 2nd finger moving gaps.
306dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
307dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue 7648: Cyapa : Resting finger plus one finger move generates a gap
308dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
309dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'resting_finger_2nd_finger_moving_gaps.dat'
310f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        score = self._test_no_gap(filename, self.criteria, lumpy, 1)
311a121b27b9145326852c5fe66e98df189c4b0fd90Joseph Hwang        self.assertTrue(score <= 0.3)
312dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
313dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
314e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwangclass PhysicalClickValidatorTest(unittest.TestCase):
315efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang    """Unit tests for PhysicalClickValidator class."""
316efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang
317efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang    def setUp(self):
318f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        self.device = lumpy
319efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        self.criteria = '== 1'
320b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang        self.mnprops = MetricNameProps()
321efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang
322efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang    def _test_physical_clicks(self, gesture_dir, files, expected_score):
323efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        gesture_path = os.path.join(unittest_path_lumpy, gesture_dir)
324efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        for filename, fingers in files.items():
325efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            packets = parse_tests_data(os.path.join(gesture_path, filename))
326efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            validator = PhysicalClickValidator(self.criteria,
327efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang                                               fingers=fingers,
328efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang                                               device=self.device)
329efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            vlog = validator.check(packets)
330efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            actual_score = vlog.score
331efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            self.assertTrue(actual_score == expected_score)
332efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang
333efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang    def test_physical_clicks_success(self):
334efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        """All physcial click files in the gesture_dir should pass."""
335efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        gesture_dir = '20130506_030025-fw_11.27-robot_sim'
336efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        gesture_path = os.path.join(unittest_path_lumpy, gesture_dir)
337efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang
338efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        # Get all 1f physical click files.
339efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        file_prefix = 'one_finger_physical_click'
340efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        fingers = 1
341efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        files1 = [(filepath, fingers) for filepath in glob.glob(
342efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            os.path.join(gesture_path, file_prefix + '*.dat'))]
343efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang
344efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        # Get all 2f physical click files.
345efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        file_prefix = 'two_fingers_physical_click'
346efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        fingers = 2
347efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        files2 = [(filepath, fingers) for filepath in glob.glob(
348efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            os.path.join(gesture_path, file_prefix + '*.dat'))]
349efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang
350efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        # files is a dictionary of {filename: fingers}
351efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        files = dict(files1 + files2)
352efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        expected_score = 1.0
353efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        self._test_physical_clicks(gesture_dir, files, expected_score)
354efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang
355efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang    def test_physical_clicks_failure(self):
356efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        """All physcial click files specified below should fail."""
357efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        gesture_dir = '20130506_032458-fw_11.23-robot_sim'
358efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        # files is a dictionary of {filename: fingers}
359efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        files = {
360efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            'one_finger_physical_click.bottom_side-lumpy-fw_11.23-complete-'
361efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang                '20130614_065744.dat': 1,
362efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            'one_finger_physical_click.center-lumpy-fw_11.23-complete-'
363efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang                '20130614_065727.dat': 1,
364efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang            'two_fingers_physical_click-lumpy-fw_11.23-complete-'
365efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang                '20130614_065757.dat': 2,
366efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        }
367efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        expected_score = 0.0
368efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang        self._test_physical_clicks(gesture_dir, files, expected_score)
369efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang
370b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang    def test_physical_clicks_by_finger_IDs(self):
371b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang        """Test that some physical clicks may come with or without correct
372b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang        finger IDs.
373b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang        """
374b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang        # files is a dictionary of {
375b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang        #     filename: (number_fingers, (actual clicks, expected clicks))}
376b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang        files = {
377b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # An incorrect case with 1 finger: the event sequence comprises
378b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value 284
379b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value -1
380b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 1
381b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 0
382b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # In this case, the BTN_LEFT occurs when there is no finger.
383b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                '1f_click_incorrect_behind_tid.dat': (1, (0, 1)),
384b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang
385b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # A correct case with 1 finger: the event sequence comprises
386b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value 284
387b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 1
388b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value -1
389b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 0
390b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # In this case, the BTN_LEFT occurs when there is no finger.
391b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                '1f_click.dat': (1, (1, 1)),
392b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang
393b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # An incorrect case with 2 fingers: the event sequence comprises
394b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value 18
395b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 1
396b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 0
397b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value 19
398b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value -1
399b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value -1
400b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # In this case, the BTN_LEFT occurs when there is only 1 finger.
401b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                '2f_clicks_incorrect_before_2nd_tid.dat': (2, (0, 1)),
402b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang
403b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # An incorrect case with 2 fingers: the event sequence comprises
404b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value 18
405b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value 19
406b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value -1
407b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value -1
408b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 1
409b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 0
410b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # In this case, the BTN_LEFT occurs when there is only 1 finger.
411b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                '2f_clicks_incorrect_behind_2_tids.dat': (2, (0, 1)),
412b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang
413b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # A correct case with 2 fingers: the event sequence comprises
414b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value 18
415b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value 19
416b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 1
417b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value -1
418b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: ABS_MT_TRACKING_ID, value -1
419b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                #   Event: BTN_LEFT, value 0
420b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                # In this case, the BTN_LEFT occurs when there is only 1 finger.
421b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                '2f_clicks.dat': (2, (1, 1)),
422b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang        }
423b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang        for filename, (fingers, expected_value) in files.items():
424b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang            packets = parse_tests_data(filename)
425b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang            validator = PhysicalClickValidator(self.criteria, fingers=fingers,
426b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                                               device=dontcare)
427b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang            vlog = validator.check(packets)
428b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang            metric_name = self.mnprops.CLICK_CHECK_TIDS.format(fingers)
429b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang            for metric in vlog.metrics:
430b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                if metric.name == metric_name:
431b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang                    self.assertEqual(metric.value, expected_value)
432b6bba8d9db954b5adbfb2eb60a220948028b4b6fJoseph Hwang
433efc137d383c3fac280e1df3b657097cd6a94e392Joseph Hwang
434e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwangclass RangeValidatorTest(unittest.TestCase):
43551b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang    """Unit tests for RangeValidator class."""
43651b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
43751b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang    def setUp(self):
438f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang        self.device = lumpy
43951b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
44051b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang    def _test_range(self, filename, expected_short_of_range_px):
44151b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        filepath = os.path.join(unittest_path_lumpy, filename)
44251b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        packets = parse_tests_data(filepath)
44351b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        validator = RangeValidator(conf.range_criteria, device=self.device)
44451b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
44551b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        # Extract the gesture variation from the filename
44651b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        variation = (filename.split('/')[-1].split('.')[1],)
44751b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
44851b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        # Determine the axis based on the direction in the gesture variation
44951b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        axis = (self.device.axis_x if validator.is_horizontal(variation)
45051b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang                else self.device.axis_y if validator.is_vertical(variation)
45151b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang                else None)
45251b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        self.assertTrue(axis is not None)
45351b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
45451b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        # Convert from pixels to mms.
45551b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        expected_short_of_range_mm = self.device.pixel_to_mm_single_axis(
45651b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang                expected_short_of_range_px, axis)
45751b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
45851b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        vlog = validator.check(packets, variation)
45951b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
46051b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        # There is only one metric in the metrics list.
46151b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        self.assertEqual(len(vlog.metrics), 1)
46251b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        actual_short_of_range_mm = vlog.metrics[0].value
46351b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        self.assertEqual(actual_short_of_range_mm, expected_short_of_range_mm)
46451b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
46551b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang    def test_range(self):
46651b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        """All physical click files specified below should fail."""
46751b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        # files_px is a dictionary of {filename: short_of_range_px}
46851b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        files_px = {
46951b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang            '20130506_030025-fw_11.27-robot_sim/'
47051b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang            'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.27-'
47151b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang                'robot_sim-20130506_031554.dat': 0,
47251b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
47351b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang            '20130506_030025-fw_11.27-robot_sim/'
47451b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang            'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.27-'
47551b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang                'robot_sim-20130506_031608.dat': 0,
47651b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
47751b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang            '20130506_032458-fw_11.23-robot_sim/'
47851b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang            'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.23-'
47951b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang                'robot_sim-20130506_032538.dat': 1,
48051b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
48151b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang            '20130506_032458-fw_11.23-robot_sim/'
48251b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang            'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.23-'
48351b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang                'robot_sim-20130506_032549.dat': 1,
48451b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        }
48551b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
48651b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang        for filename, short_of_range_px in files_px.items():
48751b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang            self._test_range(filename, short_of_range_px)
48851b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
48951b95395336cc1e887d17acab137fcd450b7bfdcJoseph Hwang
490e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwangclass StationaryFingerValidatorTest(unittest.TestCase):
491eb2c422de0873a741d68699d9f91d1ad351b9addJoseph Hwang    """Unit tests for StationaryFingerValidator class."""
492dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
493dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def setUp(self):
494e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwang        self.criteria = conf.stationary_finger_criteria
495dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
49687321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang    def _get_max_distance(self, filename, criteria, device):
497dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        packets = parse_tests_data(filename)
498dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        validator = StationaryFingerValidator(criteria, device=device)
4997981beea4b6dfdff43ca61e17b51ba295a342702Joseph Hwang        vlog = validator.check(packets)
50087321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang        return vlog.metrics[0].value
501dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
502dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_stationary_finger_shift(self):
503dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Test that the stationary shift due to 2nd finger tapping.
504dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
505dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue 7442: Cyapa : Second finger tap events influence stationary finger
506dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        position
507dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
508dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = 'stationary_finger_shift_with_2nd_finger_tap.dat'
50987321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang        max_distance = self._get_max_distance(filename, self.criteria, lumpy)
51087321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang        self.assertAlmostEqual(max_distance, 5.464430436926)
511dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
512dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang    def test_stationary_strongly_affected_by_2nd_moving_finger(self):
513dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """Test stationary finger strongly affected by 2nd moving finger with
514dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        gaps.
515dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
516dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        Issue 5812: [Cypress] reported positions of stationary finger strongly
517dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        affected by nearby moving finger
518dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        """
519dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang        filename = ('stationary_finger_strongly_affected_by_2nd_moving_finger_'
520dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang                    'with_gaps.dat')
52187321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang        max_distance = self._get_max_distance(filename, self.criteria, lumpy)
52287321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang        self.assertAlmostEqual(max_distance, 4.670861210146)
52387321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang
52487321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang
52587321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwangclass StationaryTapValidatorTest(unittest.TestCase):
52687321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang    """Unit tests for StationaryTapValidator class."""
52787321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang
52887321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang    def setUp(self):
52987321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang        self.criteria = conf.stationary_tap_criteria
53087321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang
53187321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang    def test_stationary_tap(self):
53287321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang        filenames = {'1f_click.dat': 1.718284027744,
53387321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang                     '1f_clickb.dat': 0.577590781705}
53487321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang        for filename, expected_max_distance in filenames.items():
53587321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang            packets = parse_tests_data(filename)
53687321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang            validator = StationaryTapValidator(self.criteria, device=lumpy)
53787321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang            vlog = validator.check(packets)
53887321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang            actual_max_distance = vlog.metrics[0].value
53987321559af7db87fcf4fbe5a1eb80564aecccb71Joseph Hwang            self.assertAlmostEqual(actual_max_distance, expected_max_distance)
540dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
541dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang
542e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwangclass NoLevelJumpValidatorTest(unittest.TestCase):
543cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang    """Unit tests for NoLevelJumpValidator class."""
544cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang
545cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang    def setUp(self):
546cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        self.criteria = conf.no_level_jump_criteria
547cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        self.gesture_dir = 'drag_edge_thumb'
548cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang
549cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang    def _get_score(self, filename, device):
550cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        validator = NoLevelJumpValidator(self.criteria, device=device,
551cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang                                         slots=[0,])
552cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        packets = parse_tests_data(filename, gesture_dir=self.gesture_dir)
553cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        vlog = validator.check(packets)
554ecc254fc00e6b3504d4f7d87abad937cf73a267dJoseph Hwang        score = vlog.score
555cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        return score
556cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang
557cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang    def test_level_jumps(self):
558cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        """Test files with level jumps."""
559cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        filenames = [
560cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.horizontal.dat',
561cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.horizontal_2.dat',
562cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.horizontal_3.no_points.dat',
563cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.vertical.dat',
564cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.vertical_2.dat',
565cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.diagonal.dat',
566cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        ]
567cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        for filename in filenames:
568f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang            self.assertTrue(self._get_score(filename, lumpy) <= 0.6)
569cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang
570cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang    def test_no_level_jumps(self):
571cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        """Test files without level jumps."""
572cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        filenames = [
573cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.horizontal.curvy.dat',
574cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.horizontal_2.curvy.dat',
575cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.vertical.curvy.dat',
576cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang            'drag_edge_thumb.vertical_2.curvy.dat',
577cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        ]
578cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang        for filename in filenames:
579f16a39fd38ddaec0707d9ea3b1f7c3a2a0bb090fJoseph Hwang            self.assertTrue(self._get_score(filename, lumpy) == 1.0)
580cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang
581cc906c0b5cc5849ecfb86052dac08ad90b7d3c06Joseph Hwang
582e41b3cfce09ec790d909107c9da6726e51b13c89Joseph Hwangclass ReportRateValidatorTest(unittest.TestCase):
5830d074428ab1b7cc71afd30ce1cfc863e13793fffCharlie Mooney    """Unit tests for ReportRateValidator class."""
5847b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang    def setUp(self):
5853e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        self.criteria = '>= 60'
5867b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang
5877b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang    def _get_score(self, filename, device):
588ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        validator = ReportRateValidator(self.criteria, device=device,
589ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                                        chop_off_pauses=False)
5907b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang        packets = parse_tests_data(filename)
5917b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang        vlog = validator.check(packets)
592ecc254fc00e6b3504d4f7d87abad937cf73a267dJoseph Hwang        score = vlog.score
5937b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang        return score
5947b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang
5953e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang    def test_report_rate_scores(self):
5963e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        """Test the score of the report rate."""
5977b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang        filename = '2f_scroll_diagonal.dat'
5987b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang        self.assertTrue(self._get_score(filename, device=lumpy) <= 0.5)
5997b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang
6007b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang        filename = 'one_finger_with_slot_0.dat'
6017b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang        self.assertTrue(self._get_score(filename, device=lumpy) >= 0.9)
6027b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang
6037b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang        filename = 'two_close_fingers_merging_changed_ids_gaps.dat'
6047b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang        self.assertTrue(self._get_score(filename, device=lumpy) <= 0.5)
6057b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang
606f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang    def test_report_rate_without_slot(self):
607f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        """Test report rate without specifying any slot."""
608f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        filename_report_rate_pair = [
609f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang            ('2f_scroll_diagonal.dat', 40.31),
610f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang            ('one_finger_with_slot_0.dat', 148.65),
611f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang            ('two_close_fingers_merging_changed_ids_gaps.dat', 53.12),
612f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        ]
613f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        for filename, expected_report_rate in filename_report_rate_pair:
614ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang            validator = ReportRateValidator(self.criteria, device=dontcare,
615ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                                            chop_off_pauses=False)
616f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang            validator.check(parse_tests_data(filename))
617f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang            actual_report_rate = round(validator.report_rate, 2)
618f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang            self.assertAlmostEqual(actual_report_rate, expected_report_rate)
619f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang
620f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang    def test_report_rate_with_slot(self):
621f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        """Test report rate with slot=1"""
622f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        # Compute actual_report_rate
623f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        filename = ('stationary_finger_strongly_affected_by_2nd_moving_finger_'
624f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang                    'with_gaps.dat')
625f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        validator = ReportRateValidator(self.criteria, device=dontcare,
626ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                                        finger=1, chop_off_pauses=False)
627f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        validator.check(parse_tests_data(filename))
628f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        actual_report_rate = validator.report_rate
629f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        # Compute expected_report_rate
630f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        first_syn_time = 2597.682925
63111a616bf5acd3a0f41a30f37b06c549380881b8eJoseph Hwang        last_syn_time = 2604.543335
63211a616bf5acd3a0f41a30f37b06c549380881b8eJoseph Hwang        num_packets = 592 - 1
633f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        expected_report_rate = num_packets / (last_syn_time - first_syn_time)
634f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang        self.assertAlmostEqual(actual_report_rate, expected_report_rate)
635f745c17c4bbf5f42a00813ef954762b5b8cb122cJoseph Hwang
6363e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang    def _test_report_rate_metrics(self, filename, expected_values):
637330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang        packets = parse_tests_data(filename)
638ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        validator = ReportRateValidator(self.criteria, device=lumpy,
639ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                                        chop_off_pauses=False)
6403e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        vlog = validator.check(packets)
6413e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang
642330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang        # Verify that there are 3 metrics
643330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang        number_metrics = 3
644330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang        self.assertEqual(len(vlog.metrics), number_metrics)
645330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang
6463e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        # Verify the values of the 3 metrics.
6473e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        for i in range(number_metrics):
648ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang            actual_value = vlog.metrics[i].value
649ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang            if isinstance(actual_value, tuple):
650ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                self.assertEqual(actual_value, expected_values[i])
651ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang            else:
652ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                self.assertAlmostEqual(actual_value, expected_values[i])
6533e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang
654330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang    def test_report_rate_metrics(self):
6553e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        """Test the metrics of the report rates."""
6563e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        # files is a dictionary of
657330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang        #       {filename: ((# long_intervals, # all intervals),
658330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang        #                    ave_interval, max_interval)}
6593e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        files = {
660330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang            '2f_scroll_diagonal.dat':
661330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang                ((33, 33), 24.8057272727954, 26.26600000075996),
662330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang            'one_finger_with_slot_0.dat':
663330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang                ((1, 12), 6.727166666678386, 20.411999998032115),
664330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang            'two_close_fingers_merging_changed_ids_gaps.dat':
665330dcded15b07bf1869bd5d4cbf2bccbc6a14537Joseph Hwang                ((13, 58), 18.82680942272318, 40.936946868896484),
6663e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        }
6673e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang
6683e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang        for filename, values in files.items():
6693e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang            self._test_report_rate_metrics(filename, values)
6703e04edbe5538f3f84423bc26c4a882d343e966a4Joseph Hwang
671ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang    def _test_chop_off_both_ends(self, xy_pairs, distance, expected_middle):
672ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        """Verify if the actual middle is equal to the expected middle."""
673ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        points = [Point(*xy) for xy in xy_pairs]
674ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        validator = ReportRateValidator(self.criteria, device=dontcare)
675ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        actual_middle = validator._chop_off_both_ends(points, distance)
676ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        self.assertEqual(actual_middle, expected_middle)
677ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang
678ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang    def test_chop_off_both_ends0(self):
679ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        """Test chop_off_both_ends() with distinct distances."""
680ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        xy_pairs = [
681ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                # pauses
682ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                (100, 20), (100, 21), (101, 22), (102, 24), (103, 26),
683ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                # moving segment
684ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                (120, 30), (122, 29), (123, 32), (123, 33), (126, 35),
685ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                (126, 32), (142, 29), (148, 30), (159, 31), (162, 30),
686ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                (170, 32), (183, 32), (194, 32), (205, 32), (208, 32),
687ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                # pauses
688ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang                (230, 30), (231, 31), (232, 30), (231, 30), (230, 30),
689ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        ]
690ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang
691ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        distance = 20
692ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        expected_begin_index = 5
693ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        expected_end_index = 19
694ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        expected_middle = [expected_begin_index, expected_end_index]
695ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
696ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang
697ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        distance = 0
698ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        expected_begin_index = 0
699ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        expected_end_index = len(xy_pairs) - 1
700ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        expected_middle = [expected_begin_index, expected_end_index]
701ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
702ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang
703ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang    def test_chop_off_both_ends1(self):
704ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        """Test chop_off_both_ends() with some corner cases"""
705ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        distance = 20
706ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        xy_pairs = [(120, 50), (120, 50)]
707ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        expected_middle = None
708ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
709ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang
710ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        xy_pairs = [(120, 50), (150, 52), (200, 51)]
711ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        expected_middle = [1, 1]
712ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
713ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang
714ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        xy_pairs = [(120, 50), (120, 51), (200, 52), (200, 51)]
715ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        expected_middle = None
716ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang        self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
717ceed19b0caa1913b4ca7a91b7b27d654e214bc09Joseph Hwang
7187b345e2cd5b68035db50f0a0706292cde45d9cf5Joseph Hwang
719a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwangclass HysteresisValidatorTest(unittest.TestCase):
720a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang    """Unit tests for HysteresisValidator class."""
721a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang
722a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang    def setUp(self):
723a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang        self.criteria = conf.hysteresis_criteria
724a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang
725a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang    def test_hysteresis(self):
726a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang        """Test that the hysteresis causes an initial jump."""
727a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang        filenames = {'center_to_right_normal_link.dat': 4.6043458,
728a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang                     'center_to_right_slow_link.dat': 16.8671278}
729a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang
730a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang        for filename, expected_value in filenames.items():
731a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang            packets = parse_tests_data(filename)
732a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang            validator = HysteresisValidator(self.criteria, device=link)
733a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang            vlog = validator.check(packets)
734a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang            self.assertAlmostEqual(vlog.metrics[0].value, expected_value)
735a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang
73625ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang    def test_click_data(self):
73725ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang        """Test that the validator handles None distances well.
73825ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang
73925ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang        In this test, distance1 = None and distance2 = None.
74025ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang        This results in ratio = infinity. There should be no error incurred.
74125ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang        """
74225ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang        packets = parse_tests_data('2f_clicks_test_hysteresis.dat')
74325ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang        validator = HysteresisValidator(self.criteria, device=link)
74425ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang        vlog = validator.check(packets)
74525ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang        self.assertEqual(vlog.metrics[0].value, float('infinity'))
74625ead0eae720b5e7c627e50ad214de514287aac4Joseph Hwang
747a44a9531f8dbd9c61d1f940397a816d628d4b369Joseph Hwang
74860a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwangclass MtbSanityValidatorTest(unittest.TestCase):
74960a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang    """Unit tests for MtbSanityValidator class."""
75060a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang
75160a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang    def setUp(self):
75260a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        import fake_input_device
75360a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        self.fake_device_info = fake_input_device.FakeInputDevice()
75460a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang
75560a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang    def _get_number_errors(self, filename):
75660a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        packets = parse_tests_data(filename)
75760a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        validator = MtbSanityValidator(device=link,
75860a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang                                       device_info=self.fake_device_info)
75960a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        vlog = validator.check(packets)
76060a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        number_errors, _ = vlog.metrics[1].value
76160a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        return number_errors
76260a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang
76360a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang    def test_sanity_found_errors(self):
76460a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        """Test that the tracking id is set to -1 before being assigned a
76560a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        positive value.
76660a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        """
76760a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        filenames = ['finger_crossing.top_right_to_bottom_left.slow.dat',
76860a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang                     'two_finger_tap.vertical.dat']
76960a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        for filename in filenames:
77060a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang            number_errors = self._get_number_errors(filename)
77160a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang            self.assertTrue(number_errors > 0)
77260a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang
77360a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang    def test_sanity_pass(self):
77460a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        """Test that the MTB format is correct."""
77560a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        filenames = ['2f_scroll_diagonal.dat',
77660a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang                     'drumroll_lumpy.dat']
77760a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang        for filename in filenames:
77860a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang            number_errors = self._get_number_errors(filename)
77960a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang            self.assertTrue(number_errors == 0)
78060a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang
78160a345dd2a6a7c27407153b6c9734d2b63a88c01Joseph Hwang
782e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huangclass DiscardInitialSecondsValidatorTest(unittest.TestCase):
783e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang    """Unit tests for DiscardInitialSecondsValidator class."""
784e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
785e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang    def setUp(self):
786e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        import fake_input_device
787e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        self.fake_device_info = fake_input_device.FakeInputDevice()
788e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
789e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang    def _get_score(self, filename, criteria_str):
790e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        packets = parse_tests_data(filename)
791e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        validator = DiscardInitialSecondsValidator(
792e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang            validator=CountTrackingIDValidator(criteria_str, device=link),
793e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang            device=link)
794e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        vlog = validator.check(packets)
795e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        return vlog.score
796e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
797e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang    def test_single_finger_hold(self):
798e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        """Test that the state machine reads one finger if
799e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        only one finger was held for over a second."""
800e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
801e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        filename = 'one_finger_long_hold.dat'
802e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        score = self._get_score(filename, '== 1')
803e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        self.assertTrue(score == 1)
804e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
805e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang    def test_double_finger_hold(self):
806e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        """Test that the state machine reads two fingers if
807e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        two fingers were held for over a second."""
808e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
809e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        filename = 'two_finger_long_hold.dat'
810e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        score = self._get_score(filename, '== 2')
811e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        self.assertTrue(score == 1)
812e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
813e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang    def test_double_tap_single_hold(self):
814e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        """Test that the validator discards the initial double tap and only
815e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        validates on the single finger long hold at the end.
816e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        """
817e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
818e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        filename = 'two_finger_tap_one_finger_hold.dat'
819e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        score = self._get_score(filename, '== 1')
820e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang        self.assertTrue(score == 1)
821e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
8222c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang    def test_discard_initial_seconds(self):
8232c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        """Test that discard_initial_seconds() cuts at the proper packet.
8242c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang
8252c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        Note: to print the final_state_packet, use the following statements:
8262c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang            import mtb
8272c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang            print mtb.make_pretty_packet(final_state_packet)
8282c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        """
8292c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        packets = parse_tests_data('noise_stationary_extended.dat')
8302c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        validator = DiscardInitialSecondsValidator(
8312c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang            validator=CountTrackingIDValidator('== 1', device=link),
8322c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang            device=link)
8332c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        validator.init_check(packets)
8346a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        packets = validator._discard_initial_seconds(packets, 1)
8352c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        final_state_packet = packets[0]
8362c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang
8372c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(len(final_state_packet) == 11)
8382c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        # Assert the correctness of the 1st finger data in the order of
8392c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        #     SLOT, TRACKING_ID, POSITION_X, POSITION_Y, PRESSURE
8402c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[0][MTB.EV_VALUE] == 2)
8412c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[1][MTB.EV_VALUE] == 2427)
8422c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[2][MTB.EV_VALUE] == 670)
8432c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[3][MTB.EV_VALUE] == 361)
8442c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[4][MTB.EV_VALUE] == 26)
8452c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        # Assert the correctness of the 2nd finger data in the order of
8462c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        #     SLOT, TRACKING_ID, POSITION_X, POSITION_Y, PRESSURE
8472c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[5][MTB.EV_VALUE] == 3)
8482c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[6][MTB.EV_VALUE] == 2426)
8492c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[7][MTB.EV_VALUE] == 670)
8502c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[8][MTB.EV_VALUE] == 368)
8512c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[9][MTB.EV_VALUE] == 21)
8522c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        # EVENT TIME
8532c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang        self.assertTrue(final_state_packet[0][MTB.EV_TIME] == 1412021965.723953)
8542c04d55557525b8b3dd654d64d1792f57792a91aJoseph Hwang
8556a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang    def test_get_snapshot_after_discarding_init_packets(self):
8566a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        """Test that get_snapshot() handles non-ready packet properly
8576a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        after discard_initial_seconds(). A non-ready packet is one that
8586a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        the attributes such as X, Y, and Z are not all ready.
8596a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        """
8606a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        packets = parse_tests_data('non_ready_events_in_final_state_packet.dat')
8616a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        validator = DiscardInitialSecondsValidator(
8626a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang            validator=CountTrackingIDValidator('== 1', device=link),
8636a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang            device=link)
8646a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        validator.init_check(packets)
8656a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        packets = validator._discard_initial_seconds(packets, 1)
8666a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        final_state_packet = packets[0]
8676a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang
8686a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        self.assertTrue(len(final_state_packet) == 4)
8696a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        # Assert the correctness of the finger data in the order of
8706a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        #     SLOT, TRACKING_ID, and POSITION_Y
8716a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        self.assertTrue(final_state_packet[0][MTB.EV_VALUE] == 0)
8726a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        self.assertTrue(final_state_packet[1][MTB.EV_VALUE] == 102)
8736a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        self.assertTrue(final_state_packet[2][MTB.EV_VALUE] == 1316)
8746a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        # EVENT TIME
8756a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang        self.assertTrue(final_state_packet[0][MTB.EV_TIME] == 1412888977.716634)
8766a4fc49cc298c65dc1ba48b1d7705caae9d611b1Joseph Hwang
877208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang    def test_noise_line_with_all_fingers_left(self):
878208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang        """In this test case, all fingers left. The final_state_packet is []."""
879208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang        packets=parse_tests_data('noise_line.dat')
880208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang        validator = DiscardInitialSecondsValidator(ReportRateValidator('>= 60'))
881208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang        validator.init_check(packets)
882208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang        packets = validator._discard_initial_seconds(packets, 1)
883208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang        validator.validator.init_check(packets)
884208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang        list_syn_time = validator.validator.packets.get_list_syn_time([])
885208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang        self.assertEqual(len(packets), 84)
886208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang        self.assertEqual(len(list_syn_time), 84)
887208b022eac67988d5bb35a387115c3a76f9b9413Joseph Hwang
888e99ec990bb01ce483eaabd8f0881e02e265ec686Mindy Huang
889dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwangif __name__ == '__main__':
890dc2e4066a4aa7939517db57feb854691717ff8eeJoseph Hwang  unittest.main()
891