Home | History | Annotate | Download | only in tests
      1 # Copyright (c) 2012 The Chromium OS 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 #
      5 # This module contains unit tests for the classes in the mtb module
      6 
      7 import glob
      8 import os
      9 import sys
     10 import unittest
     11 
     12 import common_unittest_utils
     13 import fuzzy
     14 import mtb
     15 import test_conf as conf
     16 
     17 from common_unittest_utils import create_mocked_devices
     18 from firmware_constants import AXIS, GV, MTB, PLATFORM, UNIT, VAL
     19 from mtb import FingerPath, TidPacket
     20 from geometry.elements import Point, about_eq
     21 
     22 
     23 unittest_path_lumpy = os.path.join(os.getcwd(), 'tests/logs/lumpy')
     24 mocked_device = create_mocked_devices()
     25 
     26 
     27 def get_mtb_packets(gesture_filename):
     28     """Get mtb_packets object by reading the gesture file."""
     29     parser = mtb.MtbParser()
     30     packets = parser.parse_file(gesture_filename)
     31     mtb_packets = mtb.Mtb(packets=packets)
     32     return mtb_packets
     33 
     34 
     35 class FakeMtb(mtb.Mtb):
     36     """A fake MTB class to set up x and y positions directly."""
     37     def __init__(self, list_x, list_y):
     38         self.list_x = list_x
     39         self.list_y = list_y
     40 
     41     def get_x_y(self, target_slot):
     42         """Return list_x, list_y directly."""
     43         return (self.list_x, self.list_y)
     44 
     45 
     46 class MtbTest(unittest.TestCase):
     47     """Unit tests for mtb.Mtb class."""
     48 
     49     def setUp(self):
     50         self.test_dir = os.path.join(os.getcwd(), 'tests')
     51         self.data_dir = os.path.join(self.test_dir, 'data')
     52 
     53     def _get_filepath(self, filename, gesture_dir=''):
     54         return os.path.join(self.data_dir, gesture_dir, filename)
     55 
     56     def _get_range_middle(self, criteria):
     57         """Get the middle range of the criteria."""
     58         fc = fuzzy.FuzzyCriteria(criteria)
     59         range_min , range_max = fc.get_criteria_value_range()
     60         range_middle = (range_min + range_max) / 2.0
     61         return range_middle
     62 
     63     def _call_get_reversed_motions(self, list_x, list_y, expected_x,
     64                                    expected_y, direction):
     65         mtb = FakeMtb(list_x, list_y)
     66         displacement = mtb.get_reversed_motions(0, direction, ratio=0.1)
     67         self.assertEqual(displacement[AXIS.X], expected_x)
     68         self.assertEqual(displacement[AXIS.Y], expected_y)
     69 
     70     def test_get_reversed_motions_no_reversed(self):
     71         list_x = (10, 22 ,36, 54, 100)
     72         list_y = (1, 2 ,6, 10, 22)
     73         self._call_get_reversed_motions(list_x, list_y, 0, 0, GV.TLBR)
     74 
     75     def test_get_reversed_motions_reversed_x_y(self):
     76         list_x = (10, 22 ,36, 154, 100)
     77         list_y = (1, 2 ,6, 30, 22)
     78         self._call_get_reversed_motions(list_x, list_y, -54, -8, GV.TLBR)
     79 
     80     def _test_get_x_y(self, filename, slot, expected_value):
     81         gesture_filename = self._get_filepath(filename)
     82         mtb_packets = get_mtb_packets(gesture_filename)
     83         list_x, list_y = mtb_packets.get_x_y(slot)
     84         points = zip(list_x, list_y)
     85         self.assertEqual(len(points), expected_value)
     86 
     87     def test_get_x_y(self):
     88         self._test_get_x_y('one_finger_with_slot_0.dat', 0, 12)
     89         self._test_get_x_y('one_finger_without_slot_0.dat', 0, 9)
     90         self._test_get_x_y('two_finger_with_slot_0.dat', 0, 121)
     91         self._test_get_x_y('two_finger_with_slot_0.dat', 1, 59)
     92         self._test_get_x_y('two_finger_without_slot_0.dat', 0, 104)
     93         self._test_get_x_y('two_finger_without_slot_0.dat', 1, 10)
     94 
     95     def test_get_pressure(self):
     96         """Test get pressure"""
     97         filename = 'one_finger_with_slot_0.dat'
     98         gesture_filename = self._get_filepath(filename)
     99         mtb_packets = get_mtb_packets(gesture_filename)
    100         finger_paths = mtb_packets.get_ordered_finger_paths()
    101 
    102         # There is only one tracking ID in the file.
    103         self.assertEqual(len(finger_paths), 1)
    104 
    105         # Verify some of the pressure values
    106         finger_path = finger_paths.values()[0]
    107         list_z = finger_path.get('pressure')
    108         self.assertEqual(list_z[0:5], [59, 57, 56, 58, 60])
    109 
    110     def test_get_x_y_multiple_slots(self):
    111         filename = 'x_y_multiple_slots.dat'
    112         filepath = self._get_filepath(filename)
    113         mtb_packets = get_mtb_packets(filepath)
    114         slots = (0, 1)
    115         list_x, list_y = mtb_packets.get_x_y_multiple_slots(slots)
    116         expected_list_x = {}
    117         expected_list_y = {}
    118         expected_list_x[0] = [1066, 1068, 1082, 1183, 1214, 1285, 1322, 1351,
    119                               1377, 1391]
    120         expected_list_y[0] = [561, 559, 542, 426, 405, 358, 328, 313, 304, 297]
    121         expected_list_x[1] = [770, 769, 768, 758, 697, 620, 585, 565, 538, 538]
    122         expected_list_y[1] = [894, 894, 895, 898, 927, 968, 996, 1003, 1013,
    123                               1013]
    124         for slot in slots:
    125             self.assertEqual(list_x[slot], expected_list_x[slot])
    126             self.assertEqual(list_y[slot], expected_list_y[slot])
    127 
    128     def test_get_x_y_multiple_slots2(self):
    129         """Test slot state machine.
    130 
    131         When the last slot in the previous packet is slot 0, and the first
    132         slot in the current packet is also slot 0, the slot 0 will not be
    133         displayed explicitly. This test ensures that the slot stat machine
    134         is tracked properly.
    135         """
    136         filename = 'pinch_to_zoom.zoom_in.dat'
    137         filepath = self._get_filepath(filename)
    138         mtb_packets = get_mtb_packets(filepath)
    139         slots = (0, 1)
    140         list_x, list_y = mtb_packets.get_x_y_multiple_slots(slots)
    141         expected_final_x = {}
    142         expected_final_y = {}
    143         expected_final_x[0] = 1318
    144         expected_final_y[0] = 255
    145         expected_final_x[1] = 522
    146         expected_final_y[1] = 1232
    147         for slot in slots:
    148             self.assertEqual(list_x[slot][-1], expected_final_x[slot])
    149             self.assertEqual(list_y[slot][-1], expected_final_y[slot])
    150 
    151     def _test_get_all_finger_paths_about_numbers_of_packets(
    152             self, filename, expected_numbers):
    153         mtb_packets = get_mtb_packets(self._get_filepath(filename))
    154         finger_paths = mtb_packets.get_ordered_finger_paths()
    155         for tid, expected_len in expected_numbers.items():
    156             self.assertEqual(len(finger_paths[tid].tid_packets), expected_len)
    157 
    158     def test_get_ordered_finger_paths_about_number_of_packets(self):
    159         self._test_get_all_finger_paths_about_numbers_of_packets(
    160                 'two_finger_with_slot_0.dat', {2101: 122, 2102: 60})
    161         self._test_get_all_finger_paths_about_numbers_of_packets(
    162                 'two_finger_without_slot_0.dat', {2097: 105, 2098: 11})
    163 
    164     def test_data_ready(self):
    165         """Test data_ready flag when point.x could be 0."""
    166         filename = ('20130506_030025-fw_11.27-robot_sim/'
    167                     'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.27-'
    168                     'robot_sim-20130506_031554.dat')
    169         filepath = os.path.join(unittest_path_lumpy, filename)
    170         mtb_packets = get_mtb_packets(filepath)
    171         points = mtb_packets.get_ordered_finger_path(0, 'point')
    172         # Note:
    173         # 1. In the first packet, there exists the event ABS_PRESSURE
    174         #    but no ABS_MT_PRESSURE.
    175         # 2. The last packet with ABS_MT_TRACKING_ID = -1 is also counted.
    176         self.assertEqual(len(points), 78)
    177 
    178     def _test_drumroll(self, filename, expected_max_distance):
    179         """expected_max_distance: unit in pixel"""
    180         gesture_filename = self._get_filepath(filename)
    181         mtb_packets = get_mtb_packets(gesture_filename)
    182         actual_max_distance = mtb_packets.get_max_distance_of_all_tracking_ids()
    183         self.assertTrue(about_eq(actual_max_distance, expected_max_distance))
    184 
    185     def test_drumroll(self):
    186         expected_max_distance = 52.0216301167
    187         self._test_drumroll('drumroll_lumpy.dat', expected_max_distance)
    188 
    189     def test_drumroll1(self):
    190         expected_max_distance = 43.5660418216
    191         self._test_drumroll('drumroll_lumpy_1.dat', expected_max_distance)
    192 
    193     def test_drumroll_link(self):
    194         expected_max_distance = 25.6124969497
    195         self._test_drumroll('drumroll_link.dat', expected_max_distance)
    196 
    197     def test_no_drumroll_link(self):
    198         expected_max_distance = 2.91547594742
    199         self._test_drumroll('no_drumroll_link.dat', expected_max_distance)
    200 
    201     def test_no_drumroll_link(self):
    202         expected_max_distance = 24.8243831746
    203         self._test_drumroll('drumroll_link_2.dat', expected_max_distance)
    204 
    205     def _test_finger_path(self, filename, tid, expected_slot, expected_data,
    206                           request_data_ready=True):
    207         """Test the data in a finger path"""
    208         # Instantiate the expected finger_path
    209         expected_finger_path = FingerPath(expected_slot,
    210                                           [TidPacket(time, Point(*xy), z)
    211                                           for time, xy, z in expected_data])
    212 
    213         # Derive the actual finger_path for the specified tid
    214         mtb_packets = get_mtb_packets(self._get_filepath(filename))
    215         finger_paths = mtb_packets.get_ordered_finger_paths(request_data_ready)
    216         actual_finger_path = finger_paths[tid]
    217 
    218         # Assert that the packet lengths are the same.
    219         self.assertEqual(len(expected_finger_path.tid_packets),
    220                          len(actual_finger_path.tid_packets))
    221 
    222         # Assert that all tid data (including syn_time, point, pressure, etc.)
    223         # in the tid packets are the same.
    224         for i in range(len(actual_finger_path.tid_packets)):
    225             expected_packet = expected_finger_path.tid_packets[i]
    226             actual_packet = actual_finger_path.tid_packets[i]
    227             self.assertEqual(expected_packet.syn_time, actual_packet.syn_time)
    228             self.assertTrue(expected_packet.point == actual_packet.point)
    229             self.assertEqual(expected_packet.pressure, actual_packet.pressure)
    230 
    231     def test_get_ordered_finger_paths(self):
    232         """Test get_ordered_finger_paths
    233 
    234         Tracking ID 95: slot 0 (no explicit slot 0 assigned).
    235                         This is the only slot in the packet.
    236         """
    237         filename = 'drumroll_link_2.dat'
    238         tid = 95
    239         expected_slot = 0
    240         expected_data = [# (syn_time,    (x,   y),   z)
    241                          (238154.686034, (789, 358), 59),
    242                          (238154.691606, (789, 358), 60),
    243                          (238154.697058, (789, 358), 57),
    244                          (238154.702576, (789, 358), 59),
    245                          (238154.713731, (789, 358), 57),
    246                          (238154.719160, (789, 359), 57),
    247                          (238154.724791, (789, 359), 56),
    248                          (238154.730111, (789, 359), 58),
    249                          (238154.735588, (788, 359), 53),
    250                          (238154.741068, (788, 360), 53),
    251                          (238154.746569, (788, 360), 49),
    252                          (238154.752108, (787, 360), 40),
    253                          (238154.757705, (787, 361), 27),
    254                          (238154.763075, (490, 903), 46),
    255                          (238154.768532, (486, 892), 61),
    256                          (238154.774695, (484, 895), 57),
    257                          (238154.780192, (493, 890), 56),
    258                          (238154.785651, (488, 893), 55),
    259                          (238154.791140, (488, 893), 56),
    260                          (238154.802080, (489, 893), 55),
    261                          (238154.807578, (490, 893), 50),
    262                          (238154.818573, (490, 893), 46),
    263                          (238154.824066, (491, 893), 36),
    264                          (238154.829525, (492, 893), 22),
    265                          (238154.849958, (492, 893), 22),
    266         ]
    267         self._test_finger_path(filename, tid, expected_slot, expected_data)
    268 
    269     def test_get_ordered_finger_paths2(self):
    270         """Test get_ordered_finger_paths
    271 
    272         Tracking ID 104: slot 0 (explicit slot 0 assigned).
    273                          This is the 2nd slot in the packet.
    274                          A slot 1 has already existed.
    275         """
    276 
    277         filename = 'drumroll_link_2.dat'
    278         tid = 104
    279         expected_slot = 0
    280         expected_data = [# (syn_time,    (x,   y),   z)
    281                          (238157.994296, (780, 373), 75),
    282                          (238158.001110, (780, 372), 75),
    283                          (238158.007128, (780, 372), 76),
    284                          (238158.012617, (780, 372), 73),
    285                          (238158.018112, (780, 373), 69),
    286                          (238158.023600, (780, 373), 68),
    287                          (238158.029542, (781, 373), 51),
    288                          (238158.049605, (781, 373), 51),
    289         ]
    290         self._test_finger_path(filename, tid, expected_slot, expected_data)
    291 
    292     def test_get_ordered_finger_paths2b(self):
    293         """Test get_ordered_finger_paths
    294 
    295         Tracking ID 103: slot 1 (explicit slot 1 assigned).
    296                          This tracking ID overlaps with two distinct
    297                          tracking IDs of which the slot is the same slot 0.
    298                          This is a good test as a multiple-finger case.
    299 
    300                          tid 102, slot 0 arrived
    301                          tid 103, slot 1 arrived
    302                          tid 102, slot 0 left
    303                          tid 104, slot 0 arrived
    304                          tid 103, slot 1 left
    305                          tid 104, slot 0 left
    306         """
    307         filename = 'drumroll_link_2.dat'
    308         tid = 103
    309         expected_slot = 1
    310         expected_data = [# (syn_time,    (x,   y),   z)
    311                          (238157.906405, (527, 901), 71),
    312                          (238157.911749, (527, 901), 74),
    313                          (238157.917247, (527, 901), 73),
    314                          (238157.923152, (527, 902), 71),
    315                          (238157.928317, (527, 902), 72),
    316                          (238157.934492, (527, 902), 71),
    317                          (238157.939984, (527, 902), 69),
    318                          (238157.945485, (527, 902), 65),
    319                          (238157.950984, (527, 902), 66),
    320                          (238157.956482, (527, 902), 70),
    321                          (238157.961976, (527, 902), 65),
    322                          (238157.973768, (527, 902), 64),
    323                          (238157.980491, (528, 901), 61),
    324                          (238157.987140, (529, 899), 60),
    325                          (238157.994296, (531, 896), 52),
    326                          (238158.001110, (534, 892), 34),
    327                          (238158.007128, (534, 892), 34),
    328                          (238158.012617, (534, 892), 34),
    329                          (238158.018112, (534, 892), 34),
    330                          (238158.023600, (534, 892), 34),
    331                          (238158.029542, (534, 892), 34),
    332         ]
    333         self._test_finger_path(filename, tid, expected_slot, expected_data)
    334 
    335     def test_get_ordered_finger_paths3(self):
    336         """Test get_ordered_finger_paths
    337 
    338         This is a good test sample.
    339         - An unusual slot 9
    340         - This is the 2nd slot in the packet. A slot 8 has already existed.
    341         - Its ABS_MT_PRESSURE is missing in the first packet.
    342         - Slot 8 terminates a few packets earlier than this slot.
    343         - Some of the ABS_MT_POSITION_X/Y and ABS_MT_PRESSURE are not shown.
    344         """
    345         filename = 'drumroll_3.dat'
    346         tid = 582
    347         expected_slot = 9
    348         expected_data = [# (syn_time,  (x,   y),   z)
    349                          (6411.371613, (682, 173), None),
    350                          (6411.382541, (667, 186), 35),
    351                          (6411.393355, (664, 189), 37),
    352                          (6411.404310, (664, 190), 38),
    353                          (6411.413015, (664, 189), 38),
    354                          (6411.422118, (665, 189), 38),
    355                          (6411.430792, (665, 189), 37),
    356                          (6411.439764, (667, 188), 36),
    357                          (6411.448484, (675, 185), 29),
    358                          (6411.457212, (683, 181), 17),
    359                          (6411.465843, (693, 172), 5),
    360                          (6411.474749, (469, 381), 6),
    361                          (6411.483702, (471, 395), 26),
    362                          (6411.492369, (471, 396), 13),
    363                          (6411.499916, (471, 396), 13),
    364         ]
    365         self._test_finger_path(filename, tid, expected_slot, expected_data,
    366                                request_data_ready=False)
    367 
    368     def test_get_ordered_finger_paths4(self):
    369         """Test get_ordered_finger_paths
    370 
    371         This test is to verify if it could handle the case when a finger-off
    372         event is followed immediately by a finger-on event in the same packet.
    373         This situation may occur occasionally in two_close_fingers_tracking
    374         gestures. Basically, this could be considered as a firmware bug.
    375         However, our test should be able to handle the situation gracefully.
    376 
    377         A problematic packet may look like:
    378 
    379         Event: time .., type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value -1
    380         Event: time .., type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 202
    381         Event: time .., type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 1577
    382         Event: time .., type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 1018
    383         Event: time .., type 3 (EV_ABS), code 58 (ABS_MT_PRESSURE), value 99
    384         Event: time .., type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 19
    385         Event: time .., type 3 (EV_ABS), code 49 (ABS_MT_TOUCH_MINOR), value 19
    386         Event: time .., type 3 (EV_ABS), code 0 (ABS_X), value 1577
    387         Event: time .., type 3 (EV_ABS), code 1 (ABS_Y), value 1018
    388         Event: time .., type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 99
    389         Event: time .., -------------- SYN_REPORT ------------
    390         """
    391         # Get the actual finger_paths from the gesture data file.
    392         filename = 'two_close_fingers_tracking.dat'
    393         mtb_packets = get_mtb_packets(self._get_filepath(filename))
    394         finger_paths = mtb_packets.get_ordered_finger_paths(
    395                 request_data_ready=False)
    396 
    397         data_list = [
    398                 # (tid, packet_idx, syn_time, (x, y), z, number_packets)
    399                 (197, -1, 1395784288.323233, (1619, 1019), 98, 435),
    400                 (202, 0, 1395784288.323233, (1577, 1018), 99, 261),
    401         ]
    402 
    403         for tid, packet_idx, syn_time, xy, z, number_packets in data_list:
    404             expected_packet = TidPacket(syn_time, Point(*xy), z)
    405 
    406             # Derive the actual finger path and the actual packet.
    407             actual_finger_path = finger_paths[tid]
    408             actual_packet = actual_finger_path.tid_packets[packet_idx]
    409 
    410             # Assert that the number of packets in the actual finger path
    411             # is equal to the specified number.
    412             self.assertEqual(number_packets,
    413                              len(actual_finger_path.tid_packets))
    414 
    415             # Assert that the expected packet is equal to the actual packet.
    416             self.assertEqual(expected_packet.syn_time, actual_packet.syn_time)
    417             self.assertTrue(expected_packet.point == actual_packet.point)
    418             self.assertEqual(expected_packet.pressure, actual_packet.pressure)
    419 
    420 
    421     def test_get_slot_data(self):
    422         """Test if it can get the data from the correct slot.
    423 
    424         slot 0 and slot 1 start at the same packet. This test verifies if the
    425         method uses the correct corresponding slot numbers.
    426         """
    427         filename = 'two_finger_tracking.diagonal.slow.dat'
    428         gesture_filename = self._get_filepath(filename)
    429         mtb_packets = get_mtb_packets(gesture_filename)
    430 
    431         # There are more packets. Use just a few of them to verify.
    432         xy_pairs = {
    433             # Slot 0
    434             0: [(1142, 191), (1144, 201), (1144, 200)],
    435             # Slot 1
    436             1: [(957, 105), (966, 106), (960, 104)],
    437         }
    438 
    439         number_packets = {
    440             # Slot 0
    441             0: 190,
    442             # Slot 1
    443             1: 189,
    444         }
    445 
    446         slots = [0, 1]
    447         for slot in slots:
    448             points = mtb_packets.get_slot_data(slot, 'point')
    449             # Verify the number of packets in each slot
    450             self.assertEqual(len(points), number_packets[slot])
    451             # Verify a few packets in each slot
    452             for i, xy_pair in enumerate(xy_pairs[slot]):
    453                 self.assertTrue(Point(*xy_pair) == points[i])
    454 
    455     def test_convert_to_evemu_format(self):
    456         evemu_filename = self._get_filepath('one_finger_swipe.evemu.dat')
    457         mtplot_filename = self._get_filepath('one_finger_swipe.dat')
    458         packets = mtb.MtbParser().parse_file(mtplot_filename)
    459         evemu_converted_iter = iter(mtb.convert_to_evemu_format(packets))
    460         with open(evemu_filename) as evemuf:
    461             for line_evemu_original in evemuf:
    462                 evemu_original = line_evemu_original.split()
    463                 evemu_converted_str = next(evemu_converted_iter, None)
    464                 self.assertNotEqual(evemu_converted_str, None)
    465                 if evemu_converted_str:
    466                     evemu_converted = evemu_converted_str.split()
    467                 self.assertEqual(len(evemu_original), 5)
    468                 self.assertEqual(len(evemu_converted), 5)
    469                 # Skip the timestamps for they are different in both formats.
    470                 # Prefix, type, code, and value should be the same.
    471                 for i in [0, 2, 3, 4]:
    472                     self.assertEqual(evemu_original[i], evemu_converted[i])
    473 
    474     def test_get_largest_gap_ratio(self):
    475         """Test get_largest_gap_ratio for one-finger and two-finger gestures."""
    476         # The following files come with noticeable large gaps.
    477         list_large_ratio = [
    478             'one_finger_tracking.left_to_right.slow_1.dat',
    479             'two_finger_gaps.vertical.dat',
    480             'two_finger_gaps.horizontal.dat',
    481             'resting_finger_2nd_finger_moving_segment_gaps.dat',
    482             'gap_new_finger_arriving_or_departing.dat',
    483             'one_stationary_finger_2nd_finger_moving_gaps.dat',
    484             'resting_finger_2nd_finger_moving_gaps.dat',
    485         ]
    486         gesture_slots = {
    487             'one_finger': [0,],
    488             'two_finger': [0, 1],
    489             'resting_finger': [1,],
    490             'gap_new_finger': [0,],
    491             'one_stationary_finger': [1,],
    492         }
    493 
    494         range_middle = self._get_range_middle(conf.no_gap_criteria)
    495         gap_data_dir = self._get_filepath('gaps')
    496         gap_data_filenames = glob.glob(os.path.join(gap_data_dir, '*.dat'))
    497         for filename in gap_data_filenames:
    498             mtb_packets = get_mtb_packets(filename)
    499             base_filename = os.path.basename(filename)
    500 
    501             # What slots to check are based on the gesture name.
    502             slots = []
    503             for gesture in gesture_slots:
    504                 if base_filename.startswith(gesture):
    505                     slots = gesture_slots[gesture]
    506                     break
    507 
    508             for slot in slots:
    509                 largest_gap_ratio = mtb_packets.get_largest_gap_ratio(slot)
    510                 if base_filename in list_large_ratio:
    511                     self.assertTrue(largest_gap_ratio >= range_middle)
    512                 else:
    513                     self.assertTrue(largest_gap_ratio < range_middle)
    514 
    515     def test_get_largest_accumulated_level_jumps(self):
    516         """Test get_largest_accumulated_level_jumps."""
    517         dir_level_jumps = 'drag_edge_thumb'
    518 
    519         filenames = [
    520             # filenames with level jumps
    521             # ----------------------------------
    522             'drag_edge_thumb.horizontal.dat',
    523             'drag_edge_thumb.horizontal_2.dat',
    524             # test no points in some tracking ID
    525             'drag_edge_thumb.horizontal_3.no_points.dat',
    526             'drag_edge_thumb.vertical.dat',
    527             'drag_edge_thumb.vertical_2.dat',
    528             'drag_edge_thumb.diagonal.dat',
    529             # Change tracking IDs quickly.
    530             'drag_edge_thumb.horizontal_4.change_ids_quickly.dat',
    531 
    532             # filenames without level jumps
    533             # ----------------------------------
    534             'drag_edge_thumb.horizontal.curvy.dat',
    535             'drag_edge_thumb.horizontal_2.curvy.dat',
    536             'drag_edge_thumb.vertical.curvy.dat',
    537             'drag_edge_thumb.vertical_2.curvy.dat',
    538             # Rather small level jumps
    539             'drag_edge_thumb.horizontal_5.small_level_jumps.curvy.dat',
    540         ]
    541 
    542         largest_level_jumps = {
    543             # Large jumps
    544             'drag_edge_thumb.horizontal.dat': {AXIS.X: 0, AXIS.Y: 97},
    545             # Smaller jumps
    546             'drag_edge_thumb.horizontal_2.dat': {AXIS.X: 0, AXIS.Y: 24},
    547             # test no points in some tracking ID
    548             'drag_edge_thumb.horizontal_3.no_points.dat':
    549                     {AXIS.X: 97, AXIS.Y: 88},
    550             # Change tracking IDs quickly.
    551             'drag_edge_thumb.horizontal_4.change_ids_quickly.dat':
    552                     {AXIS.X: 0, AXIS.Y: 14},
    553             # Large jumps
    554             'drag_edge_thumb.vertical.dat': {AXIS.X: 54, AXIS.Y: 0},
    555             # The first slot 0 comes with smaller jumps only.
    556             'drag_edge_thumb.vertical_2.dat': {AXIS.X: 20, AXIS.Y: 0},
    557             # Large jumps
    558             'drag_edge_thumb.diagonal.dat': {AXIS.X: 84, AXIS.Y: 58},
    559         }
    560 
    561         target_slot = 0
    562         for filename in filenames:
    563             filepath = self._get_filepath(filename, gesture_dir=dir_level_jumps)
    564             packets = get_mtb_packets(filepath)
    565             displacements = packets.get_displacements_for_slots(target_slot)
    566 
    567             # There are no level jumps in a curvy line.
    568             file_with_level_jump = 'curvy' not in filename
    569 
    570             # Check the first slot only
    571             tids = displacements.keys()
    572             tids.sort()
    573             tid = tids[0]
    574             # Check both axis X and axis Y
    575             for axis in AXIS.LIST:
    576                 disp = displacements[tid][axis]
    577                 jump = packets.get_largest_accumulated_level_jumps(disp)
    578                 # Verify that there are no jumps in curvy files, and
    579                 #        that there are jumps in the other files.
    580                 expected_jump = (0 if not file_with_level_jump
    581                                    else largest_level_jumps[filename][axis])
    582                 self.assertTrue(jump == expected_jump)
    583 
    584     def test_get_max_distance_from_points(self):
    585         """Test get_max_distance_from_points"""
    586         # Two farthest points: (15, 16) and (46, 70)
    587         list_coordinates_pairs = [
    588             (20, 25), (21, 35), (15, 16), (25, 22), (30, 32), (46, 70),
    589             (35, 68), (42, 53), (50, 30), (43, 69), (16, 17), (14, 30),
    590         ]
    591         points = [Point(*pairs) for pairs in list_coordinates_pairs]
    592         mtb_packets = mtb.Mtb(device=mocked_device[PLATFORM.LUMPY])
    593 
    594         # Verify the max distance in pixels
    595         max_distance_px = mtb_packets.get_max_distance_from_points(points,
    596                                                                    UNIT.PIXEL)
    597         expected_max_distance_px = ((46 - 15) ** 2 + (70 - 16) ** 2) ** 0.5
    598         self.assertAlmostEqual(max_distance_px, expected_max_distance_px)
    599 
    600         # Verify the max distance in mms
    601         max_distance_mm = mtb_packets.get_max_distance_from_points(points,
    602                                                                    UNIT.MM)
    603         expected_max_distance_mm = (((46 - 15) / 12.0) ** 2 +
    604                                     ((70 - 16) / 10.0) ** 2) ** 0.5
    605         self.assertAlmostEqual(max_distance_mm, expected_max_distance_mm)
    606 
    607     def _test_get_segments(self, list_t, list_coord, expected_segments, ratio):
    608         """Test get_segments
    609 
    610         @param expected_segments: a dictionary of
    611                 {segment_flag: expected_segment_indexes}
    612         """
    613         mtb_packets = mtb.Mtb(device=mocked_device[PLATFORM.LUMPY])
    614         for segment_flag, (expected_segment_t, expected_segment_coord) in \
    615                 expected_segments.items():
    616             segment_t, segment_coord = mtb_packets.get_segments(
    617                     list_t, list_coord, segment_flag, ratio)
    618             self.assertEqual(segment_t, expected_segment_t)
    619             self.assertEqual(segment_coord, expected_segment_coord)
    620 
    621     def test_get_segments_by_distance(self):
    622         """Test get_segments_by_distance
    623 
    624         In the test case below,
    625             min_coord = 100
    626             max_coord = 220
    627             max_distance = max_coord - min_coord = 220 - 100 = 120
    628             ratio = 0.1
    629             120 * 0.1 = 12
    630             begin segment: 100 ~ 112
    631             end segment: 208 ~ 220
    632         """
    633         list_coord = [102, 101, 101, 100, 100, 103, 104, 110, 118, 120,
    634                       122, 124, 131, 140, 150, 160, 190, 210, 217, 220]
    635         list_t = [1000 + 0.012 * i for i in range(len(list_coord))]
    636         ratio = 0.1
    637         expected_segments= {
    638                 VAL.WHOLE: (list_t, list_coord),
    639                 VAL.MIDDLE: (list_t[8:17], list_coord[8:17]),
    640                 VAL.BEGIN: (list_t[:8], list_coord[:8]),
    641                 VAL.END: (list_t[17:], list_coord[17:]),
    642         }
    643         self._test_get_segments(list_t, list_coord, expected_segments, ratio)
    644 
    645     def test_get_segments_by_length(self):
    646         """Test get_segments_by_length"""
    647         list_coords = [
    648                 [105, 105, 105, 105, 105, 105, 105, 105, 105, 105],
    649                 [104, 105, 105, 105, 105, 105, 105, 105, 105, 105],
    650                 [105, 105, 105, 105, 105, 105, 105, 105, 105, 106],
    651         ]
    652         ratio = 0.1
    653         for list_c in list_coords:
    654             list_t = [1000 + 0.012 * i for i in range(len(list_c))]
    655             expected_segments= {
    656                     VAL.WHOLE: (list_t, list_c),
    657                     VAL.MIDDLE: (list_t[1:9], list_c[1:9]),
    658                     VAL.BEGIN: (list_t[:1], list_c[:1]),
    659                     VAL.END: (list_t[9:], list_c[9:]),
    660             }
    661             self._test_get_segments(list_t, list_c, expected_segments, ratio)
    662 
    663 
    664 if __name__ == '__main__':
    665   unittest.main()
    666