blob: 66a0a36ac711e0608ec585236ba07615a2d6770b [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2020 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import unittest
from unittest import mock
from cros.factory.test.pytests import keyboard
class FakeArgs:
def __init__(self):
self.repeat_times = {}
self.skip_keycodes = [3]
self.vivaldi_keyboard = False
self.has_numpad = False
self.allow_multi_keys = False
self.sequential_press = False
self.multi_keys_delay = 0
self.layout = None
self.strict_sequential_press = False
self.board = ''
self.device_filter = None
self.skip_power_key = False
self.skip_keycodes = []
self.replacement_keymap = {}
self.detect_long_press = None
self.fn_keycodes = []
self.key_order = []
self.has_power_key = True
self.last_fn_keycode = 142
self.key_combinations = []
class KeyboardUnitTest(unittest.TestCase):
def MockFunction(self, function_name, return_value=None):
if return_value is None:
patcher = mock.patch(function_name)
else:
patcher = mock.patch(function_name, return_value=return_value)
patcher.start()
self.addCleanup(patcher.stop)
def setUp(self):
self.test = keyboard.KeyboardTest()
self.test.args = FakeArgs()
self.test.event_loop = mock.Mock()
self.test.keyboard_device = mock.Mock()
self.MockFunction('cros.factory.test.utils.evdev_utils.FindDevice')
self.MockFunction(
'cros.factory.test.utils.evdev_utils.InputDeviceDispatcher')
self.MockFunction('cros.factory.test.test_case.TestCase.ui')
self.MockFunction('cros.factory.testlog.testlog.UpdateParam')
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.PassTask')
all_keys = [[1], [2, 3], [4]]
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetLayoutKeycodes',
all_keys)
def PressKey(self, keycode):
self.PressKeys([keycode])
def PressKeys(self, keycodes):
for keycode in keycodes:
self.test.OnKeydown(keycode)
for keycode in keycodes:
self.test.OnKeyup(keycode)
@mock.patch(f'{keyboard.__name__}.KeyboardTest.PassTask')
def testPressAllKeys(self, mock_pass):
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeyboardLayout')
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeycodesInFirstRow',
[])
self.test.setUp()
self.PressKey(4)
self.PressKey(3)
self.PressKey(1)
self.PressKey(4)
mock_pass.assert_not_called()
self.PressKey(2)
mock_pass.assert_called_once()
@mock.patch(f'{keyboard.__name__}.KeyboardTest.PassTask')
def testStrictSequentialPress(self, mock_pass):
self.test.args.repeat_times = {
'default': 2,
'1': 1,
'3': 1,
'4': 3
}
self.test.args.strict_sequential_press = True
self.test.args.key_order = [1, 2, 3]
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeyboardLayout')
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeycodesInFirstRow',
[])
self.test.setUp()
self.PressKey(4)
self.PressKey(1)
self.PressKey(2)
self.PressKey(4)
self.PressKey(2)
self.PressKey(3)
mock_pass.assert_not_called()
self.PressKey(4)
mock_pass.assert_called_once()
def testStrictSequentialPressWrongOrder(self):
self.test.args.repeat_times = {
'1': 1,
'3': 2
}
self.test.args.strict_sequential_press = True
self.test.args.key_order = [1, 3, 2]
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeyboardLayout')
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeycodesInFirstRow',
[])
self.test.setUp()
self.PressKey(4)
self.PressKey(1)
self.PressKey(3)
with self.assertRaisesRegex(Exception, 'Expect keycode 3 but get 2'):
self.PressKey(2)
@mock.patch(f'{keyboard.__name__}.KeyboardTest.PassTask')
def testSequentialPress(self, mock_pass):
self.test.args.sequential_press = True
self.test.args.key_order = [1, 2, 3]
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeyboardLayout')
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeycodesInFirstRow',
[])
self.test.setUp()
self.PressKey(4)
self.PressKey(3)
self.PressKey(2)
self.PressKey(1)
self.PressKey(2)
mock_pass.assert_not_called()
self.PressKey(3)
mock_pass.assert_called_once()
@mock.patch(f'{keyboard.__name__}.KeyboardTest.PassTask')
def testKeyCombinations(self, mock_pass):
self.test.args.key_combinations = [[3], [1, 2]]
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeyboardLayout')
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeycodesInFirstRow',
[])
self.test.setUp()
self.PressKey(3)
self.PressKey(1)
self.PressKey(2)
mock_pass.assert_not_called()
self.PressKeys([2, 1])
mock_pass.assert_called_once()
@mock.patch(f'{keyboard.__name__}.KeyboardTest.PassTask')
def testSkipKeycodes(self, mock_pass):
self.test.args.skip_keycodes = [1, 2, 3]
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeyboardLayout')
self.MockFunction(f'{keyboard.__name__}.KeyboardTest.GetKeycodesInFirstRow',
[])
self.test.setUp()
self.PressKey(4)
mock_pass.assert_called_once()
def testLayoutAndBoard(self):
self.test.args.layout = 'layout'
self.test.args.board = 'board'
self.assertEqual('layout_board', self.test.GetKeyboardLayout())
def testLayoutArg(self):
self.test.args.layout = 'layout'
self.assertEqual('layout', self.test.GetKeyboardLayout())
@mock.patch.object(keyboard, 'process_utils', autospec=True)
def testLayoutVPD(self, mock_process_utils):
mock_output = mock_process_utils.CheckOutput
# The mapping is defined in platform2/regions/regions.py
for param, expect in {
'us': 'ANSI',
'jp': 'JIS',
'es': 'ISO'
}.items():
with self.subTest(param=param):
mock_output.return_value = param
self.assertEqual(expect, self.test.GetKeyboardLayout())
mock_output.assert_called_with(['vpd', '-g', 'region'])
mock_output.reset_mock()
@mock.patch(f'{keyboard.__name__}.KeyboardTest.GetVivaldiKeycodes')
def testVivaldiKeyboard(self, mock_vivaldi_keycodes):
mock_vivaldi_keycodes.return_value = [61, 62]
self.test.args.vivaldi_keyboard = True
self.test.args.fn_keycodes = [63] # should be ignored
self.assertEqual(self.test.GetKeycodesInFirstRow(), [1, 61, 62, 116])
@mock.patch('cros.factory.utils.file_utils.ReadFile')
@mock.patch(f'{keyboard.__name__}.KeyboardTest._GetKeyboardMapping')
def testSkipUnusedScancodes(self, mock_mapping, mock_read_file):
_FAKE_SCANCODES = "02 00 00 00 03 04"
self.test.args.vivaldi_keyboard = True
self.MockFunction('re.search')
mock_mapping.return_value = {
2: 2,
3: 3,
4: 4
}
mock_read_file.return_value = _FAKE_SCANCODES
self.assertEqual(self.test.GetKeycodesInFirstRow(), [1, 2, 3, 4, 116])
def testFnKeycodes(self):
self.test.args.fn_keycodes = [61, 62]
self.assertEqual(self.test.GetKeycodesInFirstRow(), [1, 61, 62, 116])
def testFnKeycodesNotHasPowerKey(self):
self.test.args.has_power_key = False
self.test.args.fn_keycodes = [61, 62]
self.assertEqual(self.test.GetKeycodesInFirstRow(), [1, 61, 62, 142])
def testDefaultNotHasPowerKey(self):
self.test.args.has_power_key = False
self.assertEqual(self.test.GetKeycodesInFirstRow(),
[1, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 142])
def testDefaultHasPowerKey(self):
self.assertEqual(self.test.GetKeycodesInFirstRow(),
[1, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 116])
def testValidLastKey(self):
self.test.args.has_power_key = False
self.test.args.last_fn_keycode = 116
self.test.GetKeycodesInFirstRow()
def testInvalidLastKey(self):
self.test.args.has_power_key = False
self.test.args.last_fn_keycode = 1
with self.assertRaises(AssertionError):
self.test.GetKeycodesInFirstRow()
if __name__ == '__main__':
unittest.main()