blob: a7054f9eac5334c717343d2e89787a5a7e81da77 [file] [log] [blame]
# 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 validators module."""
import glob
import os.path
import unittest
import common_unittest_utils
import common_util
import test_conf as conf
import validators
from common_unittest_utils import create_mocked_devices, parse_tests_data
from firmware_constants import AXIS, GV, PLATFORM, VAL
from firmware_log import MetricNameProps
from geometry.elements import Point
from touch_device import TouchDevice
from validators import (CountPacketsValidator,
CountTrackingIDValidator,
DrumrollValidator,
LinearityValidator,
NoGapValidator,
NoLevelJumpValidator,
NoReversedMotionValidator,
PhysicalClickValidator,
PinchValidator,
RangeValidator,
ReportRateValidator,
StationaryFingerValidator,
)
unittest_path_lumpy = os.path.join(os.getcwd(), 'tests/logs/lumpy')
mocked_device = create_mocked_devices()
# Make short aliases for supported platforms
alex = mocked_device[PLATFORM.ALEX]
lumpy = mocked_device[PLATFORM.LUMPY]
link = mocked_device[PLATFORM.LINK]
# Some tests do not care what device is used.
dontcare = 'dontcare'
class BaseValidatorTest(unittest.TestCase):
"""A base class for all ValidatorTest classes."""
def setUp(self, show_spec_v2_flag=False):
"""Set up mocked devices for various test boards.
@param show_spec_v2_flag: this flag indicates if we are using spec v2.
"""
validators.set_show_spec_v2(show_spec_v2_flag)
def tearDown(self):
"""Reset the show_spec_v2 so that other unit tests for spec v1 could be
conducted as uaual.
"""
validators.set_show_spec_v2(False)
class CountTrackingIDValidatorTest(BaseValidatorTest):
"""Unit tests for CountTrackingIDValidator class."""
def setUp(self):
super(CountTrackingIDValidatorTest, self).setUp()
def _test_count_tracking_id(self, filename, criteria, device):
packets = parse_tests_data(filename)
validator = CountTrackingIDValidator(criteria, device=device)
vlog = validator.check(packets)
return vlog.score
def test_two_finger_id_change(self):
"""Two two fingers id change.
Issue 7867: Cyapa : Two finger scroll, tracking ids change
"""
filename = 'two_finger_id_change.dat'
score = self._test_count_tracking_id(filename, '== 2', lumpy)
self.assertTrue(score == 0)
def test_one_finger_fast_swipe_id_split(self):
"""One finger fast swipe resulting in IDs split.
Issue: 7869: Lumpy: Tracking ID reassigned during quick-2F-swipe
"""
filename = 'one_finger_fast_swipe_id_split.dat'
score = self._test_count_tracking_id(filename, '== 1', lumpy)
self.assertTrue(score == 0)
def test_two_fingers_fast_flick_id_split(self):
"""Two figners fast flick resulting in IDs split.
Issue: 7869: Lumpy: Tracking ID reassigned during quick-2F-swipe
"""
filename = 'two_finger_fast_flick_id_split.dat'
score = self._test_count_tracking_id(filename, '== 2', lumpy)
self.assertTrue(score == 0)
class DrumrollValidatorTest(BaseValidatorTest):
"""Unit tests for DrumrollValidator class."""
def setUp(self):
super(DrumrollValidatorTest, self).setUp()
self.criteria = conf.drumroll_criteria
def _test_drumroll(self, filename, criteria, device):
packets = parse_tests_data(filename)
validator = DrumrollValidator(criteria, device=device)
vlog = validator.check(packets)
return vlog.score
def _get_drumroll_metrics(self, filename, criteria, device):
packets = parse_tests_data(filename, gesture_dir=unittest_path_lumpy)
validator = DrumrollValidator(criteria, device=device)
metrics = validator.check(packets).metrics
return metrics
def test_drumroll_lumpy(self):
"""Should catch the drumroll on lumpy.
Issue 7809: Lumpy: Drumroll bug in firmware
Max distance: 52.02 px
"""
filename = 'drumroll_lumpy.dat'
score = self._test_drumroll(filename, self.criteria, lumpy)
self.assertTrue(score == 0)
def test_drumroll_lumpy_1(self):
"""Should catch the drumroll on lumpy.
Issue 7809: Lumpy: Drumroll bug in firmware
Max distance: 43.57 px
"""
filename = 'drumroll_lumpy_1.dat'
score = self._test_drumroll(filename, self.criteria, lumpy)
self.assertTrue(score <= 0.15)
def test_no_drumroll_link(self):
"""Should pass (score == 1) when there is no drumroll.
Issue 7809: Lumpy: Drumroll bug in firmware
Max distance: 2.92 px
"""
filename = 'no_drumroll_link.dat'
score = self._test_drumroll(filename, self.criteria, link)
self.assertTrue(score == 1)
def test_drumroll_metrics(self):
"""Test the drumroll metrics."""
expected_max_values = {
'20130506_030025-fw_11.27-robot_sim/'
'drumroll.fast-lumpy-fw_11.27-manual-20130528_044804.dat':
2.29402908535,
'20130506_030025-fw_11.27-robot_sim/'
'drumroll.fast-lumpy-fw_11.27-manual-20130528_044820.dat':
0.719567771497,
'20130506_031746-fw_11.27-robot_sim/'
'drumroll.fast-lumpy-fw_11.27-manual-20130528_044728.dat':
0.833491481592,
'20130506_032458-fw_11.23-robot_sim/'
'drumroll.fast-lumpy-fw_11.23-manual-20130528_044856.dat':
1.18368539364,
'20130506_032458-fw_11.23-robot_sim/'
'drumroll.fast-lumpy-fw_11.23-manual-20130528_044907.dat':
0.851161282019,
'20130506_032659-fw_11.23-robot_sim/'
'drumroll.fast-lumpy-fw_11.23-manual-20130528_044933.dat':
2.64245519251,
'20130506_032659-fw_11.23-robot_sim/'
'drumroll.fast-lumpy-fw_11.23-manual-20130528_044947.dat':
0.910624022916,
}
criteria = self.criteria
for filename, expected_max_value in expected_max_values.items():
metrics = self._get_drumroll_metrics(filename, criteria, lumpy)
actual_max_value = max([m.value for m in metrics])
self.assertAlmostEqual(expected_max_value, actual_max_value)
class LinearityValidatorTest(BaseValidatorTest):
"""Unit tests for LinearityValidator class."""
def setUp(self):
super(LinearityValidatorTest, self).setUp()
self.criteria = conf.linearity_criteria
validators.show_new_spec = False
def _test_linearity_criteria(self, criteria_str, fingers, device):
filename = '2f_scroll_diagonal.dat'
direction = GV.DIAGONAL
packets = parse_tests_data(filename)
scores = {}
for finger in fingers:
validator = LinearityValidator(criteria_str, device=device,
finger=finger)
scores[finger] = validator.check(packets, direction).score
return scores
def test_linearity_criteria0(self):
"""The scores are 0s due to strict criteria."""
criteria_str = '<= 0.01, ~ +0.01'
scores = self._test_linearity_criteria(criteria_str, (0, 1), alex)
self.assertTrue(scores[0] == 0)
self.assertTrue(scores[1] == 0)
def test_linearity_criteria1(self):
"""The validator gets score betwee 0 and 1."""
criteria_str = '<= 0.01, ~ +3.0'
scores = self._test_linearity_criteria(criteria_str, (0, 1), alex)
self.assertTrue(scores[0] > 0 and scores[0] < 1)
self.assertTrue(scores[1] > 0 and scores[1] < 1)
def test_linearity_criteria2(self):
"""The validator gets score of 1 due to very relaxed criteria."""
criteria_str = '<= 10, ~ +10'
scores = self._test_linearity_criteria(criteria_str, (0, 1), alex)
self.assertTrue(scores[0] == 1)
self.assertTrue(scores[1] == 1)
def _test_linearity_validator(self, filename, criteria, fingers, device,
direction):
packets = parse_tests_data(filename)
scores = {}
if isinstance(fingers, int):
fingers = (fingers,)
for finger in fingers:
validator = LinearityValidator(criteria, device=device,
finger=finger)
scores[finger] = validator.check(packets, direction).score
return scores
def test_two_finger_jagged_lines(self):
"""Test two-finger jagged lines."""
filename = 'two_finger_tracking.diagonal.slow.dat'
scores = self._test_linearity_validator(filename, self.criteria, (0, 1),
lumpy, GV.DIAGONAL)
self.assertTrue(scores[0] < 0.7)
self.assertTrue(scores[1] < 0.7)
def test_stationary_finger_fat_finger_wobble(self):
"""Test fat finger horizontal move with a stationary resting finger
results in a wobble.
Issue 7551: Fat finger horizontal move with a stationary resting
finger results in a wobble.
"""
filename = 'stationary_finger_fat_finger_wobble.dat'
scores = self._test_linearity_validator(filename, self.criteria, 1,
lumpy, GV.HORIZONTAL)
self.assertTrue(scores[1] <= 0.1)
def test_thumb_edge(self):
"""Test thumb edge wobble.
Issue 7554: thumb edge behavior.
"""
filename = 'thumb_edge_wobble.dat'
scores = self._test_linearity_validator(filename, self.criteria, 0,
lumpy, GV.HORIZONTAL)
self.assertTrue(scores[0] < 0.5)
def test_two_close_fingers_merging_changed_ids_gaps(self):
"""Test close finger merging - causes id changes
Issue 7555: close finger merging - causes id changes.
"""
filename = 'two_close_fingers_merging_changed_ids_gaps.dat'
scores = self._test_linearity_validator(filename, self.criteria, 0,
lumpy, GV.VERTICAL)
self.assertTrue(scores[0] < 0.3)
def test_jagged_two_finger_scroll(self):
"""Test jagged two finger scroll.
Issue 7650: Cyapa : poor two fat fingers horizontal scroll performance -
jagged lines
"""
filename = 'jagged_two_finger_scroll_horizontal.dat'
scores = self._test_linearity_validator(filename, self.criteria, (0, 1),
lumpy, GV.HORIZONTAL)
self.assertTrue(scores[0] < 0.3)
self.assertTrue(scores[1] < 0.3)
def test_first_point_jump(self):
"""Test the first point jump
At finger 0, the positions of (x, y) looks like
x: 208, 241, 242, 245, 246, ...
y: 551, 594, 595, 597, 598, ...
Note that the the first y position is a jump.
"""
filename = 'two_finger_tracking.bottom_left_to_top_right.slow.dat'
scores = self._test_linearity_validator(filename, self.criteria, 0,
lumpy, GV.DIAGONAL)
self.assertTrue(scores[0] < 0.3)
def test_simple_linear_regression0(self):
validator = LinearityValidator('<= 0.2, ~ +0.3', device=lumpy, finger=0)
validator.init_check()
# A perfect line from bottom left to top right
list_x = [1, 2, 3, 4, 5, 6, 7, 8]
list_y = [20, 40, 60, 80, 100, 120, 140, 160]
spmse = validator._simple_linear_regression(list_x, list_y)
self.assertEqual(spmse, 0)
def test_simple_linear_regression1(self):
validator = LinearityValidator('<= 0.2, ~ +0.3', device=lumpy, finger=0)
validator.init_check()
# Another perfect line from top left to bottom right
list_x = [1, 2, 3, 4, 5, 6, 7, 8]
list_y = [160, 140, 120, 100, 80, 60, 40, 20]
spmse = validator._simple_linear_regression(list_x, list_y)
self.assertEqual(spmse, 0)
def test_simple_linear_regression2(self):
validator = LinearityValidator('<= 0.2, ~ +0.3', device=lumpy, finger=0)
validator.init_check()
# An outlier in y axis
list_x = [1, 2, 3, 4, 5, 6, 7, 8]
list_y = [20, 40, 60, 70, 100, 120, 140, 160]
spmse = validator._simple_linear_regression(list_x, list_y)
self.assertTrue(spmse > 0)
def test_simple_linear_regression3(self):
validator = LinearityValidator('<= 0.2, ~ +0.3', device=lumpy, finger=0)
validator.init_check()
# Repeated values in x axis
list_x = [1, 2, 2, 4, 5, 6, 7, 8]
list_y = [20, 40, 60, 80, 100, 120, 140, 160]
spmse = validator._simple_linear_regression(list_x, list_y)
self.assertTrue(spmse > 0)
class LinearityValidator2Test(BaseValidatorTest):
"""Unit tests for LinearityValidator2 class."""
def setUp(self):
super(LinearityValidator2Test, self).setUp(show_spec_v2_flag=True)
self.validator = LinearityValidator(conf.linearity_criteria,
device=lumpy, finger=0)
self.validator.init_check()
def test_simple_linear_regression0(self):
"""A perfect y-t line from bottom left to top right"""
list_y = [20, 40, 60, 80, 100, 120, 140, 160]
list_t = [i * 0.1 for i in range(len(list_y))]
(max_err_px, rms_err_px) = self.validator._calc_errors_single_axis(
list_t, list_y)
self.assertAlmostEqual(max_err_px, 0)
self.assertAlmostEqual(rms_err_px, 0)
def test_simple_linear_regression0b(self):
"""An imperfect y-t line from bottom left to top right with
the first and the last entries as outliers.
In this test case:
begin segment = [1,]
end segment = [188, 190]
middle segment = [20, 40, 60, 80, 100, 120, 140, 160]
the simple linear regression line is calculated based on the
middle segment, and is
y = 20 * t
the error = [1, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10]
"""
list_y = [1, 20, 40, 60, 80, 100, 120, 140, 160, 188, 190]
list_t = range(len(list_y))
expected_errs_dict = {
VAL.WHOLE: [1, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10],
VAL.BEGIN: [1, ],
VAL.END: [8, 10],
VAL.BOTH_ENDS: [1, 8, 10],
}
for segment_flag, expected_errs in expected_errs_dict.items():
self.validator._segments= segment_flag
(max_err, rms_err) = self.validator._calc_errors_single_axis(list_t,
list_y)
expected_max_err = max(expected_errs)
expected_rms_err = (sum([i ** 2 for i in expected_errs]) /
len(expected_errs)) ** 0.5
self.assertAlmostEqual(max_err, expected_max_err)
self.assertAlmostEqual(rms_err, expected_rms_err)
def test_log_details_and_metrics(self):
"""Test the axes in _log_details_and_metrics"""
# gesture_dir: tests/data/linearity
gesture_dir = 'linearity'
filenames_axes = {
'two_finger_tracking.right_to_left.slow-lumpy-fw_11.27-robot-'
'20130227_204458.dat': [AXIS.X],
'one_finger_to_edge.center_to_top.slow-lumpy-fw_11.27-robot-'
'20130227_203228.dat': [AXIS.Y],
'two_finger_tracking.bottom_left_to_top_right.normal-lumpy-'
'fw_11.27-robot-20130227_204902.dat': [AXIS.X, AXIS.Y],
}
for filename, expected_axes in filenames_axes.items():
packets = parse_tests_data(filename, gesture_dir=gesture_dir)
# get the direction of the gesture
direction = [filename.split('-')[0].split('.')[1]]
self.validator.check(packets, direction)
actual_axes = sorted(self.validator.list_coords.keys())
self.assertEqual(actual_axes, expected_axes)
def _test_simple_linear_regression1(self):
"""A y-t line taken from a real example.
Refer to the "Numerical example" in the wiki page:
http://en.wikipedia.org/wiki/Simple_linear_regression
"""
list_t = [1.47, 1.50, 1.52, 1.55, 1.57, 1.60, 1.63, 1.65, 1.68, 1.70,
1.73, 1.75, 1.78, 1.80, 1.83]
list_y = [52.21, 53.12, 54.48, 55.84, 57.20, 58.57, 59.93, 61.29,
63.11, 64.47, 66.28, 68.10, 69.92, 72.19, 74.46]
expected_max_err = 1.3938545467809007
expected_rms_err = 0.70666155991311708
(max_err, rms_err) = self.validator._calc_errors_single_axis(
list_t, list_y)
self.assertAlmostEqual(max_err, expected_max_err)
self.assertAlmostEqual(rms_err, expected_rms_err)
class NoGapValidatorTest(BaseValidatorTest):
"""Unit tests for NoGapValidator class."""
GAPS_SUBDIR = 'gaps'
def setUp(self):
super(NoGapValidatorTest, self).setUp()
self.criteria = conf.no_gap_criteria
def _test_no_gap(self, filename, criteria, device, slot):
file_subpath = os.path.join(self.GAPS_SUBDIR, filename)
packets = parse_tests_data(file_subpath)
validator = NoGapValidator(criteria, device=device, slot=slot)
vlog = validator.check(packets)
return vlog.score
def test_two_finger_scroll_gaps(self):
"""Test that there are gaps in the two finger scroll gesture.
Issue 7552: Cyapa : two finger scroll motion produces gaps in tracking
"""
filename = 'two_finger_gaps.horizontal.dat'
score0 = self._test_no_gap(filename, self.criteria, lumpy, 0)
score1 = self._test_no_gap(filename, self.criteria, lumpy, 1)
self.assertTrue(score0 <= 0.1)
self.assertTrue(score1 <= 0.1)
def test_gap_new_finger_arriving_or_departing(self):
"""Test gap when new finger arriving or departing.
Issue: 8005: Cyapa : gaps appear when new finger arrives or departs
"""
filename = 'gap_new_finger_arriving_or_departing.dat'
score = self._test_no_gap(filename, self.criteria, lumpy, 0)
self.assertTrue(score <= 0.3)
def test_one_stationary_finger_2nd_finger_moving_gaps(self):
"""Test one stationary finger resulting in 2nd finger moving gaps."""
filename = 'one_stationary_finger_2nd_finger_moving_gaps.dat'
score = self._test_no_gap(filename, self.criteria, lumpy, 1)
self.assertTrue(score <= 0.1)
def test_resting_finger_2nd_finger_moving_gaps(self):
"""Test resting finger resulting in 2nd finger moving gaps.
Issue 7648: Cyapa : Resting finger plus one finger move generates a gap
"""
filename = 'resting_finger_2nd_finger_moving_gaps.dat'
score = self._test_no_gap(filename, self.criteria, lumpy, 1)
self.assertTrue(score <= 0.3)
class PhysicalClickValidatorTest(BaseValidatorTest):
"""Unit tests for PhysicalClickValidator class."""
def setUp(self):
super(PhysicalClickValidatorTest, self).setUp()
self.device = lumpy
self.criteria = '== 1'
self.mnprops = MetricNameProps()
def _test_physical_clicks(self, gesture_dir, files, expected_score):
gesture_path = os.path.join(unittest_path_lumpy, gesture_dir)
for filename, fingers in files.items():
packets = parse_tests_data(os.path.join(gesture_path, filename))
validator = PhysicalClickValidator(self.criteria,
fingers=fingers,
device=self.device)
vlog = validator.check(packets)
actual_score = vlog.score
self.assertTrue(actual_score == expected_score)
def test_physical_clicks_success(self):
"""All physcial click files in the gesture_dir should pass."""
gesture_dir = '20130506_030025-fw_11.27-robot_sim'
gesture_path = os.path.join(unittest_path_lumpy, gesture_dir)
# Get all 1f physical click files.
file_prefix = 'one_finger_physical_click'
fingers = 1
files1 = [(filepath, fingers) for filepath in glob.glob(
os.path.join(gesture_path, file_prefix + '*.dat'))]
# Get all 2f physical click files.
file_prefix = 'two_fingers_physical_click'
fingers = 2
files2 = [(filepath, fingers) for filepath in glob.glob(
os.path.join(gesture_path, file_prefix + '*.dat'))]
# files is a dictionary of {filename: fingers}
files = dict(files1 + files2)
expected_score = 1.0
self._test_physical_clicks(gesture_dir, files, expected_score)
def test_physical_clicks_failure(self):
"""All physcial click files specified below should fail."""
gesture_dir = '20130506_032458-fw_11.23-robot_sim'
# files is a dictionary of {filename: fingers}
files = {
'one_finger_physical_click.bottom_side-lumpy-fw_11.23-complete-'
'20130614_065744.dat': 1,
'one_finger_physical_click.center-lumpy-fw_11.23-complete-'
'20130614_065727.dat': 1,
'two_fingers_physical_click-lumpy-fw_11.23-complete-'
'20130614_065757.dat': 2,
}
expected_score = 0.0
self._test_physical_clicks(gesture_dir, files, expected_score)
def test_physical_clicks_by_finger_IDs(self):
"""Test that some physical clicks may come with or without correct
finger IDs.
"""
# files is a dictionary of {
# filename: (number_fingers, (actual clicks, expected clicks))}
files = {
# An incorrect case with 1 finger: the event sequence comprises
# Event: ABS_MT_TRACKING_ID, value 284
# Event: ABS_MT_TRACKING_ID, value -1
# Event: BTN_LEFT, value 1
# Event: BTN_LEFT, value 0
# In this case, the BTN_LEFT occurs when there is no finger.
'1f_click_incorrect_behind_tid.dat': (1, (0, 1)),
# A correct case with 1 finger: the event sequence comprises
# Event: ABS_MT_TRACKING_ID, value 284
# Event: BTN_LEFT, value 1
# Event: ABS_MT_TRACKING_ID, value -1
# Event: BTN_LEFT, value 0
# In this case, the BTN_LEFT occurs when there is no finger.
'1f_click.dat': (1, (1, 1)),
# An incorrect case with 2 fingers: the event sequence comprises
# Event: ABS_MT_TRACKING_ID, value 18
# Event: BTN_LEFT, value 1
# Event: BTN_LEFT, value 0
# Event: ABS_MT_TRACKING_ID, value 19
# Event: ABS_MT_TRACKING_ID, value -1
# Event: ABS_MT_TRACKING_ID, value -1
# In this case, the BTN_LEFT occurs when there is only 1 finger.
'2f_clicks_incorrect_before_2nd_tid.dat': (2, (0, 1)),
# An incorrect case with 2 fingers: the event sequence comprises
# Event: ABS_MT_TRACKING_ID, value 18
# Event: ABS_MT_TRACKING_ID, value 19
# Event: ABS_MT_TRACKING_ID, value -1
# Event: ABS_MT_TRACKING_ID, value -1
# Event: BTN_LEFT, value 1
# Event: BTN_LEFT, value 0
# In this case, the BTN_LEFT occurs when there is only 1 finger.
'2f_clicks_incorrect_behind_2_tids.dat': (2, (0, 1)),
# A correct case with 2 fingers: the event sequence comprises
# Event: ABS_MT_TRACKING_ID, value 18
# Event: ABS_MT_TRACKING_ID, value 19
# Event: BTN_LEFT, value 1
# Event: ABS_MT_TRACKING_ID, value -1
# Event: ABS_MT_TRACKING_ID, value -1
# Event: BTN_LEFT, value 0
# In this case, the BTN_LEFT occurs when there is only 1 finger.
'2f_clicks.dat': (2, (1, 1)),
}
for filename, (fingers, expected_value) in files.items():
packets = parse_tests_data(filename)
validator = PhysicalClickValidator(self.criteria, fingers=fingers,
device=dontcare)
vlog = validator.check(packets)
metric_name = self.mnprops.CLICK_CHECK_TIDS.format(fingers)
for metric in vlog.metrics:
if metric.name == metric_name:
self.assertEqual(metric.value, expected_value)
class RangeValidatorTest(BaseValidatorTest):
"""Unit tests for RangeValidator class."""
def setUp(self):
super(RangeValidatorTest, self).setUp()
self.device = lumpy
def _test_range(self, filename, expected_short_of_range_px):
filepath = os.path.join(unittest_path_lumpy, filename)
packets = parse_tests_data(filepath)
validator = RangeValidator(conf.range_criteria, device=self.device)
# Extract the gesture variation from the filename
variation = (filename.split('/')[-1].split('.')[1],)
# Determine the axis based on the direction in the gesture variation
axis = (self.device.axis_x if validator.is_horizontal(variation)
else self.device.axis_y if validator.is_vertical(variation)
else None)
self.assertTrue(axis is not None)
# Convert from pixels to mms.
expected_short_of_range_mm = self.device.pixel_to_mm_single_axis(
expected_short_of_range_px, axis)
vlog = validator.check(packets, variation)
# There is only one metric in the metrics list.
self.assertEqual(len(vlog.metrics), 1)
actual_short_of_range_mm = vlog.metrics[0].value
self.assertEqual(actual_short_of_range_mm, expected_short_of_range_mm)
def test_range(self):
"""All physical click files specified below should fail."""
# files_px is a dictionary of {filename: short_of_range_px}
files_px = {
'20130506_030025-fw_11.27-robot_sim/'
'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.27-'
'robot_sim-20130506_031554.dat': 0,
'20130506_030025-fw_11.27-robot_sim/'
'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.27-'
'robot_sim-20130506_031608.dat': 0,
'20130506_032458-fw_11.23-robot_sim/'
'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.23-'
'robot_sim-20130506_032538.dat': 1,
'20130506_032458-fw_11.23-robot_sim/'
'one_finger_to_edge.center_to_left.slow-lumpy-fw_11.23-'
'robot_sim-20130506_032549.dat': 1,
}
for filename, short_of_range_px in files_px.items():
self._test_range(filename, short_of_range_px)
class StationaryFingerValidatorTest(BaseValidatorTest):
"""Unit tests for StationaryFingerValidator class."""
def setUp(self):
super(StationaryFingerValidatorTest, self).setUp(show_spec_v2_flag=True)
self.criteria = conf.stationary_finger_criteria()
def _test_stationary_finger(self, filename, criteria, device):
packets = parse_tests_data(filename)
validator = StationaryFingerValidator(criteria, device=device)
vlog = validator.check(packets)
return vlog.score
def test_stationary_finger_shift(self):
"""Test that the stationary shift due to 2nd finger tapping.
Issue 7442: Cyapa : Second finger tap events influence stationary finger
position
"""
filename = 'stationary_finger_shift_with_2nd_finger_tap.dat'
score = self._test_stationary_finger(filename, self.criteria, lumpy)
self.assertTrue(score <= 0.1)
def test_stationary_strongly_affected_by_2nd_moving_finger(self):
"""Test stationary finger strongly affected by 2nd moving finger with
gaps.
Issue 5812: [Cypress] reported positions of stationary finger strongly
affected by nearby moving finger
"""
filename = ('stationary_finger_strongly_affected_by_2nd_moving_finger_'
'with_gaps.dat')
score = self._test_stationary_finger(filename, self.criteria, lumpy)
self.assertTrue(score <= 0.1)
class NoLevelJumpValidatorTest(BaseValidatorTest):
"""Unit tests for NoLevelJumpValidator class."""
def setUp(self):
super(NoLevelJumpValidatorTest, self).setUp()
self.criteria = conf.no_level_jump_criteria
self.gesture_dir = 'drag_edge_thumb'
def _get_score(self, filename, device):
validator = NoLevelJumpValidator(self.criteria, device=device,
slots=[0,])
packets = parse_tests_data(filename, gesture_dir=self.gesture_dir)
vlog = validator.check(packets)
score = vlog.score
return score
def test_level_jumps(self):
"""Test files with level jumps."""
filenames = [
'drag_edge_thumb.horizontal.dat',
'drag_edge_thumb.horizontal_2.dat',
'drag_edge_thumb.horizontal_3.no_points.dat',
'drag_edge_thumb.vertical.dat',
'drag_edge_thumb.vertical_2.dat',
'drag_edge_thumb.diagonal.dat',
]
for filename in filenames:
self.assertTrue(self._get_score(filename, lumpy) <= 0.6)
def test_no_level_jumps(self):
"""Test files without level jumps."""
filenames = [
'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',
]
for filename in filenames:
self.assertTrue(self._get_score(filename, lumpy) == 1.0)
class ReportRateValidatorTest(BaseValidatorTest):
"""Unit tests for ReportRateValidator class."""
def setUp(self):
super(ReportRateValidatorTest, self).setUp()
self.criteria = '>= 60'
def _get_score(self, filename, device):
validator = ReportRateValidator(self.criteria, device=device,
chop_off_pauses=False)
packets = parse_tests_data(filename)
vlog = validator.check(packets)
score = vlog.score
return score
def test_report_rate_scores(self):
"""Test the score of the report rate."""
filename = '2f_scroll_diagonal.dat'
self.assertTrue(self._get_score(filename, device=lumpy) <= 0.5)
filename = 'one_finger_with_slot_0.dat'
self.assertTrue(self._get_score(filename, device=lumpy) >= 0.9)
filename = 'two_close_fingers_merging_changed_ids_gaps.dat'
self.assertTrue(self._get_score(filename, device=lumpy) <= 0.5)
def test_report_rate_without_slot(self):
"""Test report rate without specifying any slot."""
filename_report_rate_pair = [
('2f_scroll_diagonal.dat', 40.31),
('one_finger_with_slot_0.dat', 148.65),
('two_close_fingers_merging_changed_ids_gaps.dat', 53.12),
]
for filename, expected_report_rate in filename_report_rate_pair:
validator = ReportRateValidator(self.criteria, device=dontcare,
chop_off_pauses=False)
validator.check(parse_tests_data(filename))
actual_report_rate = round(validator.report_rate, 2)
self.assertAlmostEqual(actual_report_rate, expected_report_rate)
def test_report_rate_with_slot(self):
"""Test report rate with slot=1"""
# Compute actual_report_rate
filename = ('stationary_finger_strongly_affected_by_2nd_moving_finger_'
'with_gaps.dat')
validator = ReportRateValidator(self.criteria, device=dontcare,
finger=1, chop_off_pauses=False)
validator.check(parse_tests_data(filename))
actual_report_rate = validator.report_rate
# Compute expected_report_rate
first_syn_time = 2597.682925
last_syn_time = 2604.543335
num_packets = 592 - 1
expected_report_rate = num_packets / (last_syn_time - first_syn_time)
self.assertAlmostEqual(actual_report_rate, expected_report_rate)
def _test_report_rate_metrics(self, filename, expected_values):
packets = parse_tests_data(filename)
validator = ReportRateValidator(self.criteria, device=lumpy,
chop_off_pauses=False)
vlog = validator.check(packets)
# Verify that there are 3 metrics
number_metrics = 3
self.assertEqual(len(vlog.metrics), number_metrics)
# Verify the values of the 3 metrics.
for i in range(number_metrics):
actual_value = vlog.metrics[i].value
if isinstance(actual_value, tuple):
self.assertEqual(actual_value, expected_values[i])
else:
self.assertAlmostEqual(actual_value, expected_values[i])
def test_report_rate_metrics(self):
"""Test the metrics of the report rates."""
# files is a dictionary of
# {filename: ((# long_intervals, # all intervals),
# ave_interval, max_interval)}
files = {
'2f_scroll_diagonal.dat':
((33, 33), 24.8057272727954, 26.26600000075996),
'one_finger_with_slot_0.dat':
((1, 12), 6.727166666678386, 20.411999998032115),
'two_close_fingers_merging_changed_ids_gaps.dat':
((13, 58), 18.82680942272318, 40.936946868896484),
}
for filename, values in files.items():
self._test_report_rate_metrics(filename, values)
def _test_chop_off_both_ends(self, xy_pairs, distance, expected_middle):
"""Verify if the actual middle is equal to the expected middle."""
points = [Point(*xy) for xy in xy_pairs]
validator = ReportRateValidator(self.criteria, device=dontcare)
actual_middle = validator._chop_off_both_ends(points, distance)
self.assertEqual(actual_middle, expected_middle)
def test_chop_off_both_ends0(self):
"""Test chop_off_both_ends() with distinct distances."""
xy_pairs = [
# pauses
(100, 20), (100, 21), (101, 22), (102, 24), (103, 26),
# moving segment
(120, 30), (122, 29), (123, 32), (123, 33), (126, 35),
(126, 32), (142, 29), (148, 30), (159, 31), (162, 30),
(170, 32), (183, 32), (194, 32), (205, 32), (208, 32),
# pauses
(230, 30), (231, 31), (232, 30), (231, 30), (230, 30),
]
distance = 20
expected_begin_index = 5
expected_end_index = 19
expected_middle = [expected_begin_index, expected_end_index]
self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
distance = 0
expected_begin_index = 0
expected_end_index = len(xy_pairs) - 1
expected_middle = [expected_begin_index, expected_end_index]
self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
def test_chop_off_both_ends1(self):
"""Test chop_off_both_ends() with some corner cases"""
distance = 20
xy_pairs = [(120, 50), (120, 50)]
expected_middle = None
self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
xy_pairs = [(120, 50), (150, 52), (200, 51)]
expected_middle = [1, 1]
self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
xy_pairs = [(120, 50), (120, 51), (200, 52), (200, 51)]
expected_middle = None
self._test_chop_off_both_ends(xy_pairs, distance, expected_middle)
if __name__ == '__main__':
unittest.main()