| # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| # |
| # This module contains unit tests for the classes in the mtb module |
| |
| import glob |
| import os |
| import sys |
| import unittest |
| |
| import common_unittest_utils |
| import fuzzy |
| import mtb |
| import test_conf as conf |
| |
| from common_unittest_utils import create_mocked_devices |
| from firmware_constants import AXIS, GV, MTB, PLATFORM, UNIT, VAL |
| from mtb import FingerPath, TidPacket |
| from geometry.elements import Point, about_eq |
| |
| |
| unittest_path_lumpy = os.path.join(os.getcwd(), 'tests/logs/lumpy') |
| mocked_device = create_mocked_devices() |
| |
| |
| def get_mtb_packets(gesture_filename): |
| """Get mtb_packets object by reading the gesture file.""" |
| parser = mtb.MtbParser() |
| packets = parser.parse_file(gesture_filename) |
| mtb_packets = mtb.Mtb(packets=packets) |
| return mtb_packets |
| |
| |
| class FakeMtb(mtb.Mtb): |
| """A fake MTB class to set up x and y positions directly.""" |
| def __init__(self, list_x, list_y): |
| self.list_x = list_x |
| self.list_y = list_y |
| |
| def get_x_y(self, target_slot): |
| """Return list_x, list_y directly.""" |
| return (self.list_x, self.list_y) |
| |
| |
| class MtbTest(unittest.TestCase): |
| """Unit tests for mtb.Mtb class.""" |
| |
| def setUp(self): |
| self.test_dir = os.path.join(os.getcwd(), 'tests') |
| self.data_dir = os.path.join(self.test_dir, 'data') |
| |
| def _get_filepath(self, filename, gesture_dir=''): |
| return os.path.join(self.data_dir, gesture_dir, filename) |
| |
| def _get_range_middle(self, criteria): |
| """Get the middle range of the criteria.""" |
| fc = fuzzy.FuzzyCriteria(criteria) |
| range_min , range_max = fc.get_criteria_value_range() |
| range_middle = (range_min + range_max) / 2.0 |
| return range_middle |
| |
| def _call_get_reversed_motions(self, list_x, list_y, expected_x, |
| expected_y, direction): |
| mtb = FakeMtb(list_x, list_y) |
| displacement = mtb.get_reversed_motions(0, direction, ratio=0.1) |
| self.assertEqual(displacement[AXIS.X], expected_x) |
| self.assertEqual(displacement[AXIS.Y], expected_y) |
| |
| def test_get_reversed_motions_no_reversed(self): |
| list_x = (10, 22 ,36, 54, 100) |
| list_y = (1, 2 ,6, 10, 22) |
| self._call_get_reversed_motions(list_x, list_y, 0, 0, GV.TLBR) |
| |
| def test_get_reversed_motions_reversed_x_y(self): |
| list_x = (10, 22 ,36, 154, 100) |
| list_y = (1, 2 ,6, 30, 22) |
| self._call_get_reversed_motions(list_x, list_y, -54, -8, GV.TLBR) |
| |
| def _test_get_x_y(self, filename, slot, expected_value): |
| gesture_filename = self._get_filepath(filename) |
| mtb_packets = get_mtb_packets(gesture_filename) |
| list_x, list_y = mtb_packets.get_x_y(slot) |
| points = zip(list_x, list_y) |
| self.assertEqual(len(points), expected_value) |
| |
| def test_get_x_y(self): |
| self._test_get_x_y('one_finger_with_slot_0.dat', 0, 12) |
| self._test_get_x_y('one_finger_without_slot_0.dat', 0, 9) |
| self._test_get_x_y('two_finger_with_slot_0.dat', 0, 121) |
| self._test_get_x_y('two_finger_with_slot_0.dat', 1, 59) |
| self._test_get_x_y('two_finger_without_slot_0.dat', 0, 104) |
| self._test_get_x_y('two_finger_without_slot_0.dat', 1, 10) |
| |
| def test_get_pressure(self): |
| """Test get pressure""" |
| filename = 'one_finger_with_slot_0.dat' |
| gesture_filename = self._get_filepath(filename) |
| mtb_packets = get_mtb_packets(gesture_filename) |
| finger_paths = mtb_packets.get_ordered_finger_paths() |
| |
| # There is only one tracking ID in the file. |
| self.assertEqual(len(finger_paths), 1) |
| |
| # Verify some of the pressure values |
| finger_path = finger_paths.values()[0] |
| list_z = finger_path.get('pressure') |
| self.assertEqual(list_z[0:5], [59, 57, 56, 58, 60]) |
| |
| def test_get_x_y_multiple_slots(self): |
| filename = 'x_y_multiple_slots.dat' |
| filepath = self._get_filepath(filename) |
| mtb_packets = get_mtb_packets(filepath) |
| slots = (0, 1) |
| list_x, list_y = mtb_packets.get_x_y_multiple_slots(slots) |
| expected_list_x = {} |
| expected_list_y = {} |
| expected_list_x[0] = [1066, 1068, 1082, 1183, 1214, 1285, 1322, 1351, |
| 1377, 1391] |
| expected_list_y[0] = [561, 559, 542, 426, 405, 358, 328, 313, 304, 297] |
| expected_list_x[1] = [770, 769, 768, 758, 697, 620, 585, 565, 538, 538] |
| expected_list_y[1] = [894, 894, 895, 898, 927, 968, 996, 1003, 1013, |
| 1013] |
| for slot in slots: |
| self.assertEqual(list_x[slot], expected_list_x[slot]) |
| self.assertEqual(list_y[slot], expected_list_y[slot]) |
| |
| def test_get_x_y_multiple_slots2(self): |
| """Test slot state machine. |
| |
| When the last slot in the previous packet is slot 0, and the first |
| slot in the current packet is also slot 0, the slot 0 will not be |
| displayed explicitly. This test ensures that the slot stat machine |
| is tracked properly. |
| """ |
| filename = 'pinch_to_zoom.zoom_in.dat' |
| filepath = self._get_filepath(filename) |
| mtb_packets = get_mtb_packets(filepath) |
| slots = (0, 1) |
| list_x, list_y = mtb_packets.get_x_y_multiple_slots(slots) |
| expected_final_x = {} |
| expected_final_y = {} |
| expected_final_x[0] = 1318 |
| expected_final_y[0] = 255 |
| expected_final_x[1] = 522 |
| expected_final_y[1] = 1232 |
| for slot in slots: |
| self.assertEqual(list_x[slot][-1], expected_final_x[slot]) |
| self.assertEqual(list_y[slot][-1], expected_final_y[slot]) |
| |
| def _test_get_all_finger_paths_about_numbers_of_packets( |
| self, filename, expected_numbers): |
| mtb_packets = get_mtb_packets(self._get_filepath(filename)) |
| finger_paths = mtb_packets.get_ordered_finger_paths() |
| for tid, expected_len in expected_numbers.items(): |
| self.assertEqual(len(finger_paths[tid].tid_packets), expected_len) |
| |
| def test_get_ordered_finger_paths_about_number_of_packets(self): |
| self._test_get_all_finger_paths_about_numbers_of_packets( |
| 'two_finger_with_slot_0.dat', {2101: 122, 2102: 60}) |
| self._test_get_all_finger_paths_about_numbers_of_packets( |
| 'two_finger_without_slot_0.dat', {2097: 105, 2098: 11}) |
| |
| def test_data_ready(self): |
| """Test data_ready flag when point.x could be 0.""" |
| filename = ('20130506_030025-fw_11.27-robot_sim/' |
| 'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.27-' |
| 'robot_sim-20130506_031554.dat') |
| filepath = os.path.join(unittest_path_lumpy, filename) |
| mtb_packets = get_mtb_packets(filepath) |
| points = mtb_packets.get_ordered_finger_path(0, 'point') |
| # Note: |
| # 1. In the first packet, there exists the event ABS_PRESSURE |
| # but no ABS_MT_PRESSURE. |
| # 2. The last packet with ABS_MT_TRACKING_ID = -1 is also counted. |
| self.assertEqual(len(points), 78) |
| |
| def _test_drumroll(self, filename, expected_max_distance): |
| """expected_max_distance: unit in pixel""" |
| gesture_filename = self._get_filepath(filename) |
| mtb_packets = get_mtb_packets(gesture_filename) |
| actual_max_distance = mtb_packets.get_max_distance_of_all_tracking_ids() |
| self.assertTrue(about_eq(actual_max_distance, expected_max_distance)) |
| |
| def test_drumroll(self): |
| expected_max_distance = 52.0216301167 |
| self._test_drumroll('drumroll_lumpy.dat', expected_max_distance) |
| |
| def test_drumroll1(self): |
| expected_max_distance = 43.5660418216 |
| self._test_drumroll('drumroll_lumpy_1.dat', expected_max_distance) |
| |
| def test_drumroll_link(self): |
| expected_max_distance = 25.6124969497 |
| self._test_drumroll('drumroll_link.dat', expected_max_distance) |
| |
| def test_no_drumroll_link(self): |
| expected_max_distance = 2.91547594742 |
| self._test_drumroll('no_drumroll_link.dat', expected_max_distance) |
| |
| def test_no_drumroll_link(self): |
| expected_max_distance = 24.8243831746 |
| self._test_drumroll('drumroll_link_2.dat', expected_max_distance) |
| |
| def _test_finger_path(self, filename, tid, expected_slot, expected_data, |
| request_data_ready=True): |
| """Test the data in a finger path""" |
| # Instantiate the expected finger_path |
| expected_finger_path = FingerPath(expected_slot, |
| [TidPacket(time, Point(*xy), z) |
| for time, xy, z in expected_data]) |
| |
| # Derive the actual finger_path for the specified tid |
| mtb_packets = get_mtb_packets(self._get_filepath(filename)) |
| finger_paths = mtb_packets.get_ordered_finger_paths(request_data_ready) |
| actual_finger_path = finger_paths[tid] |
| |
| # Assert that the packet lengths are the same. |
| self.assertEqual(len(expected_finger_path.tid_packets), |
| len(actual_finger_path.tid_packets)) |
| |
| # Assert that all tid data (including syn_time, point, pressure, etc.) |
| # in the tid packets are the same. |
| for i in range(len(actual_finger_path.tid_packets)): |
| expected_packet = expected_finger_path.tid_packets[i] |
| actual_packet = actual_finger_path.tid_packets[i] |
| self.assertEqual(expected_packet.syn_time, actual_packet.syn_time) |
| self.assertTrue(expected_packet.point == actual_packet.point) |
| self.assertEqual(expected_packet.pressure, actual_packet.pressure) |
| |
| def test_get_ordered_finger_paths(self): |
| """Test get_ordered_finger_paths |
| |
| Tracking ID 95: slot 0 (no explicit slot 0 assigned). |
| This is the only slot in the packet. |
| """ |
| filename = 'drumroll_link_2.dat' |
| tid = 95 |
| expected_slot = 0 |
| expected_data = [# (syn_time, (x, y), z) |
| (238154.686034, (789, 358), 59), |
| (238154.691606, (789, 358), 60), |
| (238154.697058, (789, 358), 57), |
| (238154.702576, (789, 358), 59), |
| (238154.713731, (789, 358), 57), |
| (238154.719160, (789, 359), 57), |
| (238154.724791, (789, 359), 56), |
| (238154.730111, (789, 359), 58), |
| (238154.735588, (788, 359), 53), |
| (238154.741068, (788, 360), 53), |
| (238154.746569, (788, 360), 49), |
| (238154.752108, (787, 360), 40), |
| (238154.757705, (787, 361), 27), |
| (238154.763075, (490, 903), 46), |
| (238154.768532, (486, 892), 61), |
| (238154.774695, (484, 895), 57), |
| (238154.780192, (493, 890), 56), |
| (238154.785651, (488, 893), 55), |
| (238154.791140, (488, 893), 56), |
| (238154.802080, (489, 893), 55), |
| (238154.807578, (490, 893), 50), |
| (238154.818573, (490, 893), 46), |
| (238154.824066, (491, 893), 36), |
| (238154.829525, (492, 893), 22), |
| (238154.849958, (492, 893), 22), |
| ] |
| self._test_finger_path(filename, tid, expected_slot, expected_data) |
| |
| def test_get_ordered_finger_paths2(self): |
| """Test get_ordered_finger_paths |
| |
| Tracking ID 104: slot 0 (explicit slot 0 assigned). |
| This is the 2nd slot in the packet. |
| A slot 1 has already existed. |
| """ |
| |
| filename = 'drumroll_link_2.dat' |
| tid = 104 |
| expected_slot = 0 |
| expected_data = [# (syn_time, (x, y), z) |
| (238157.994296, (780, 373), 75), |
| (238158.001110, (780, 372), 75), |
| (238158.007128, (780, 372), 76), |
| (238158.012617, (780, 372), 73), |
| (238158.018112, (780, 373), 69), |
| (238158.023600, (780, 373), 68), |
| (238158.029542, (781, 373), 51), |
| (238158.049605, (781, 373), 51), |
| ] |
| self._test_finger_path(filename, tid, expected_slot, expected_data) |
| |
| def test_get_ordered_finger_paths2b(self): |
| """Test get_ordered_finger_paths |
| |
| Tracking ID 103: slot 1 (explicit slot 1 assigned). |
| This tracking ID overlaps with two distinct |
| tracking IDs of which the slot is the same slot 0. |
| This is a good test as a multiple-finger case. |
| |
| tid 102, slot 0 arrived |
| tid 103, slot 1 arrived |
| tid 102, slot 0 left |
| tid 104, slot 0 arrived |
| tid 103, slot 1 left |
| tid 104, slot 0 left |
| """ |
| filename = 'drumroll_link_2.dat' |
| tid = 103 |
| expected_slot = 1 |
| expected_data = [# (syn_time, (x, y), z) |
| (238157.906405, (527, 901), 71), |
| (238157.911749, (527, 901), 74), |
| (238157.917247, (527, 901), 73), |
| (238157.923152, (527, 902), 71), |
| (238157.928317, (527, 902), 72), |
| (238157.934492, (527, 902), 71), |
| (238157.939984, (527, 902), 69), |
| (238157.945485, (527, 902), 65), |
| (238157.950984, (527, 902), 66), |
| (238157.956482, (527, 902), 70), |
| (238157.961976, (527, 902), 65), |
| (238157.973768, (527, 902), 64), |
| (238157.980491, (528, 901), 61), |
| (238157.987140, (529, 899), 60), |
| (238157.994296, (531, 896), 52), |
| (238158.001110, (534, 892), 34), |
| (238158.007128, (534, 892), 34), |
| (238158.012617, (534, 892), 34), |
| (238158.018112, (534, 892), 34), |
| (238158.023600, (534, 892), 34), |
| (238158.029542, (534, 892), 34), |
| ] |
| self._test_finger_path(filename, tid, expected_slot, expected_data) |
| |
| def test_get_ordered_finger_paths3(self): |
| """Test get_ordered_finger_paths |
| |
| This is a good test sample. |
| - An unusual slot 9 |
| - This is the 2nd slot in the packet. A slot 8 has already existed. |
| - Its ABS_MT_PRESSURE is missing in the first packet. |
| - Slot 8 terminates a few packets earlier than this slot. |
| - Some of the ABS_MT_POSITION_X/Y and ABS_MT_PRESSURE are not shown. |
| """ |
| filename = 'drumroll_3.dat' |
| tid = 582 |
| expected_slot = 9 |
| expected_data = [# (syn_time, (x, y), z) |
| (6411.371613, (682, 173), None), |
| (6411.382541, (667, 186), 35), |
| (6411.393355, (664, 189), 37), |
| (6411.404310, (664, 190), 38), |
| (6411.413015, (664, 189), 38), |
| (6411.422118, (665, 189), 38), |
| (6411.430792, (665, 189), 37), |
| (6411.439764, (667, 188), 36), |
| (6411.448484, (675, 185), 29), |
| (6411.457212, (683, 181), 17), |
| (6411.465843, (693, 172), 5), |
| (6411.474749, (469, 381), 6), |
| (6411.483702, (471, 395), 26), |
| (6411.492369, (471, 396), 13), |
| (6411.499916, (471, 396), 13), |
| ] |
| self._test_finger_path(filename, tid, expected_slot, expected_data, |
| request_data_ready=False) |
| |
| def test_get_ordered_finger_paths4(self): |
| """Test get_ordered_finger_paths |
| |
| This test is to verify if it could handle the case when a finger-off |
| event is followed immediately by a finger-on event in the same packet. |
| This situation may occur occasionally in two_close_fingers_tracking |
| gestures. Basically, this could be considered as a firmware bug. |
| However, our test should be able to handle the situation gracefully. |
| |
| A problematic packet may look like: |
| |
| Event: time .., type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value -1 |
| Event: time .., type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 202 |
| Event: time .., type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 1577 |
| Event: time .., type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 1018 |
| Event: time .., type 3 (EV_ABS), code 58 (ABS_MT_PRESSURE), value 99 |
| Event: time .., type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 19 |
| Event: time .., type 3 (EV_ABS), code 49 (ABS_MT_TOUCH_MINOR), value 19 |
| Event: time .., type 3 (EV_ABS), code 0 (ABS_X), value 1577 |
| Event: time .., type 3 (EV_ABS), code 1 (ABS_Y), value 1018 |
| Event: time .., type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 99 |
| Event: time .., -------------- SYN_REPORT ------------ |
| """ |
| # Get the actual finger_paths from the gesture data file. |
| filename = 'two_close_fingers_tracking.dat' |
| mtb_packets = get_mtb_packets(self._get_filepath(filename)) |
| finger_paths = mtb_packets.get_ordered_finger_paths( |
| request_data_ready=False) |
| |
| data_list = [ |
| # (tid, packet_idx, syn_time, (x, y), z, number_packets) |
| (197, -1, 1395784288.323233, (1619, 1019), 98, 435), |
| (202, 0, 1395784288.323233, (1577, 1018), 99, 261), |
| ] |
| |
| for tid, packet_idx, syn_time, xy, z, number_packets in data_list: |
| expected_packet = TidPacket(syn_time, Point(*xy), z) |
| |
| # Derive the actual finger path and the actual packet. |
| actual_finger_path = finger_paths[tid] |
| actual_packet = actual_finger_path.tid_packets[packet_idx] |
| |
| # Assert that the number of packets in the actual finger path |
| # is equal to the specified number. |
| self.assertEqual(number_packets, |
| len(actual_finger_path.tid_packets)) |
| |
| # Assert that the expected packet is equal to the actual packet. |
| self.assertEqual(expected_packet.syn_time, actual_packet.syn_time) |
| self.assertTrue(expected_packet.point == actual_packet.point) |
| self.assertEqual(expected_packet.pressure, actual_packet.pressure) |
| |
| |
| def test_get_slot_data(self): |
| """Test if it can get the data from the correct slot. |
| |
| slot 0 and slot 1 start at the same packet. This test verifies if the |
| method uses the correct corresponding slot numbers. |
| """ |
| filename = 'two_finger_tracking.diagonal.slow.dat' |
| gesture_filename = self._get_filepath(filename) |
| mtb_packets = get_mtb_packets(gesture_filename) |
| |
| # There are more packets. Use just a few of them to verify. |
| xy_pairs = { |
| # Slot 0 |
| 0: [(1142, 191), (1144, 201), (1144, 200)], |
| # Slot 1 |
| 1: [(957, 105), (966, 106), (960, 104)], |
| } |
| |
| number_packets = { |
| # Slot 0 |
| 0: 190, |
| # Slot 1 |
| 1: 189, |
| } |
| |
| slots = [0, 1] |
| for slot in slots: |
| points = mtb_packets.get_slot_data(slot, 'point') |
| # Verify the number of packets in each slot |
| self.assertEqual(len(points), number_packets[slot]) |
| # Verify a few packets in each slot |
| for i, xy_pair in enumerate(xy_pairs[slot]): |
| self.assertTrue(Point(*xy_pair) == points[i]) |
| |
| def test_convert_to_evemu_format(self): |
| evemu_filename = self._get_filepath('one_finger_swipe.evemu.dat') |
| mtplot_filename = self._get_filepath('one_finger_swipe.dat') |
| packets = mtb.MtbParser().parse_file(mtplot_filename) |
| evemu_converted_iter = iter(mtb.convert_to_evemu_format(packets)) |
| with open(evemu_filename) as evemuf: |
| for line_evemu_original in evemuf: |
| evemu_original = line_evemu_original.split() |
| evemu_converted_str = next(evemu_converted_iter, None) |
| self.assertNotEqual(evemu_converted_str, None) |
| if evemu_converted_str: |
| evemu_converted = evemu_converted_str.split() |
| self.assertEqual(len(evemu_original), 5) |
| self.assertEqual(len(evemu_converted), 5) |
| # Skip the timestamps for they are different in both formats. |
| # Prefix, type, code, and value should be the same. |
| for i in [0, 2, 3, 4]: |
| self.assertEqual(evemu_original[i], evemu_converted[i]) |
| |
| def test_get_largest_gap_ratio(self): |
| """Test get_largest_gap_ratio for one-finger and two-finger gestures.""" |
| # The following files come with noticeable large gaps. |
| list_large_ratio = [ |
| 'one_finger_tracking.left_to_right.slow_1.dat', |
| 'two_finger_gaps.vertical.dat', |
| 'two_finger_gaps.horizontal.dat', |
| 'resting_finger_2nd_finger_moving_segment_gaps.dat', |
| 'gap_new_finger_arriving_or_departing.dat', |
| 'one_stationary_finger_2nd_finger_moving_gaps.dat', |
| 'resting_finger_2nd_finger_moving_gaps.dat', |
| ] |
| gesture_slots = { |
| 'one_finger': [0,], |
| 'two_finger': [0, 1], |
| 'resting_finger': [1,], |
| 'gap_new_finger': [0,], |
| 'one_stationary_finger': [1,], |
| } |
| |
| range_middle = self._get_range_middle(conf.no_gap_criteria) |
| gap_data_dir = self._get_filepath('gaps') |
| gap_data_filenames = glob.glob(os.path.join(gap_data_dir, '*.dat')) |
| for filename in gap_data_filenames: |
| mtb_packets = get_mtb_packets(filename) |
| base_filename = os.path.basename(filename) |
| |
| # What slots to check are based on the gesture name. |
| slots = [] |
| for gesture in gesture_slots: |
| if base_filename.startswith(gesture): |
| slots = gesture_slots[gesture] |
| break |
| |
| for slot in slots: |
| largest_gap_ratio = mtb_packets.get_largest_gap_ratio(slot) |
| if base_filename in list_large_ratio: |
| self.assertTrue(largest_gap_ratio >= range_middle) |
| else: |
| self.assertTrue(largest_gap_ratio < range_middle) |
| |
| def test_get_largest_accumulated_level_jumps(self): |
| """Test get_largest_accumulated_level_jumps.""" |
| dir_level_jumps = 'drag_edge_thumb' |
| |
| filenames = [ |
| # filenames with level jumps |
| # ---------------------------------- |
| 'drag_edge_thumb.horizontal.dat', |
| 'drag_edge_thumb.horizontal_2.dat', |
| # test no points in some tracking ID |
| 'drag_edge_thumb.horizontal_3.no_points.dat', |
| 'drag_edge_thumb.vertical.dat', |
| 'drag_edge_thumb.vertical_2.dat', |
| 'drag_edge_thumb.diagonal.dat', |
| # Change tracking IDs quickly. |
| 'drag_edge_thumb.horizontal_4.change_ids_quickly.dat', |
| |
| # filenames without level jumps |
| # ---------------------------------- |
| 'drag_edge_thumb.horizontal.curvy.dat', |
| 'drag_edge_thumb.horizontal_2.curvy.dat', |
| 'drag_edge_thumb.vertical.curvy.dat', |
| 'drag_edge_thumb.vertical_2.curvy.dat', |
| # Rather small level jumps |
| 'drag_edge_thumb.horizontal_5.small_level_jumps.curvy.dat', |
| ] |
| |
| largest_level_jumps = { |
| # Large jumps |
| 'drag_edge_thumb.horizontal.dat': {AXIS.X: 0, AXIS.Y: 97}, |
| # Smaller jumps |
| 'drag_edge_thumb.horizontal_2.dat': {AXIS.X: 0, AXIS.Y: 24}, |
| # test no points in some tracking ID |
| 'drag_edge_thumb.horizontal_3.no_points.dat': |
| {AXIS.X: 97, AXIS.Y: 88}, |
| # Change tracking IDs quickly. |
| 'drag_edge_thumb.horizontal_4.change_ids_quickly.dat': |
| {AXIS.X: 0, AXIS.Y: 14}, |
| # Large jumps |
| 'drag_edge_thumb.vertical.dat': {AXIS.X: 54, AXIS.Y: 0}, |
| # The first slot 0 comes with smaller jumps only. |
| 'drag_edge_thumb.vertical_2.dat': {AXIS.X: 20, AXIS.Y: 0}, |
| # Large jumps |
| 'drag_edge_thumb.diagonal.dat': {AXIS.X: 84, AXIS.Y: 58}, |
| } |
| |
| target_slot = 0 |
| for filename in filenames: |
| filepath = self._get_filepath(filename, gesture_dir=dir_level_jumps) |
| packets = get_mtb_packets(filepath) |
| displacements = packets.get_displacements_for_slots(target_slot) |
| |
| # There are no level jumps in a curvy line. |
| file_with_level_jump = 'curvy' not in filename |
| |
| # Check the first slot only |
| tids = displacements.keys() |
| tids.sort() |
| tid = tids[0] |
| # Check both axis X and axis Y |
| for axis in AXIS.LIST: |
| disp = displacements[tid][axis] |
| jump = packets.get_largest_accumulated_level_jumps(disp) |
| # Verify that there are no jumps in curvy files, and |
| # that there are jumps in the other files. |
| expected_jump = (0 if not file_with_level_jump |
| else largest_level_jumps[filename][axis]) |
| self.assertTrue(jump == expected_jump) |
| |
| def test_get_max_distance_from_points(self): |
| """Test get_max_distance_from_points""" |
| # Two farthest points: (15, 16) and (46, 70) |
| list_coordinates_pairs = [ |
| (20, 25), (21, 35), (15, 16), (25, 22), (30, 32), (46, 70), |
| (35, 68), (42, 53), (50, 30), (43, 69), (16, 17), (14, 30), |
| ] |
| points = [Point(*pairs) for pairs in list_coordinates_pairs] |
| mtb_packets = mtb.Mtb(device=mocked_device[PLATFORM.LUMPY]) |
| |
| # Verify the max distance in pixels |
| max_distance_px = mtb_packets.get_max_distance_from_points(points, |
| UNIT.PIXEL) |
| expected_max_distance_px = ((46 - 15) ** 2 + (70 - 16) ** 2) ** 0.5 |
| self.assertAlmostEqual(max_distance_px, expected_max_distance_px) |
| |
| # Verify the max distance in mms |
| max_distance_mm = mtb_packets.get_max_distance_from_points(points, |
| UNIT.MM) |
| expected_max_distance_mm = (((46 - 15) / 12.0) ** 2 + |
| ((70 - 16) / 10.0) ** 2) ** 0.5 |
| self.assertAlmostEqual(max_distance_mm, expected_max_distance_mm) |
| |
| def _test_get_segments(self, list_t, list_coord, expected_segments, ratio): |
| """Test get_segments |
| |
| @param expected_segments: a dictionary of |
| {segment_flag: expected_segment_indexes} |
| """ |
| mtb_packets = mtb.Mtb(device=mocked_device[PLATFORM.LUMPY]) |
| for segment_flag, (expected_segment_t, expected_segment_coord) in \ |
| expected_segments.items(): |
| segment_t, segment_coord = mtb_packets.get_segments( |
| list_t, list_coord, segment_flag, ratio) |
| self.assertEqual(segment_t, expected_segment_t) |
| self.assertEqual(segment_coord, expected_segment_coord) |
| |
| def test_get_segments_by_distance(self): |
| """Test get_segments_by_distance |
| |
| In the test case below, |
| min_coord = 100 |
| max_coord = 220 |
| max_distance = max_coord - min_coord = 220 - 100 = 120 |
| ratio = 0.1 |
| 120 * 0.1 = 12 |
| begin segment: 100 ~ 112 |
| end segment: 208 ~ 220 |
| """ |
| list_coord = [102, 101, 101, 100, 100, 103, 104, 110, 118, 120, |
| 122, 124, 131, 140, 150, 160, 190, 210, 217, 220] |
| list_t = [1000 + 0.012 * i for i in range(len(list_coord))] |
| ratio = 0.1 |
| expected_segments= { |
| VAL.WHOLE: (list_t, list_coord), |
| VAL.MIDDLE: (list_t[8:17], list_coord[8:17]), |
| VAL.BEGIN: (list_t[:8], list_coord[:8]), |
| VAL.END: (list_t[17:], list_coord[17:]), |
| } |
| self._test_get_segments(list_t, list_coord, expected_segments, ratio) |
| |
| def test_get_segments_by_length(self): |
| """Test get_segments_by_length""" |
| list_coords = [ |
| [105, 105, 105, 105, 105, 105, 105, 105, 105, 105], |
| [104, 105, 105, 105, 105, 105, 105, 105, 105, 105], |
| [105, 105, 105, 105, 105, 105, 105, 105, 105, 106], |
| ] |
| ratio = 0.1 |
| for list_c in list_coords: |
| list_t = [1000 + 0.012 * i for i in range(len(list_c))] |
| expected_segments= { |
| VAL.WHOLE: (list_t, list_c), |
| VAL.MIDDLE: (list_t[1:9], list_c[1:9]), |
| VAL.BEGIN: (list_t[:1], list_c[:1]), |
| VAL.END: (list_t[9:], list_c[9:]), |
| } |
| self._test_get_segments(list_t, list_c, expected_segments, ratio) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |