1import string 2import unittest 3 4from _pyrepl.keymap import _keynames, _escapes, parse_keys, compile_keymap, KeySpecError 5 6 7class TestParseKeys(unittest.TestCase): 8 def test_single_character(self): 9 """Ensure that single ascii characters or single digits are parsed as single characters.""" 10 test_cases = [(key, [key]) for key in string.ascii_letters + string.digits] 11 for test_key, expected_keys in test_cases: 12 with self.subTest(f"{test_key} should be parsed as {expected_keys}"): 13 self.assertEqual(parse_keys(test_key), expected_keys) 14 15 def test_keynames(self): 16 """Ensure that keynames are parsed to their corresponding mapping. 17 18 A keyname is expected to be of the following form: \\<keyname> such as \\<left> 19 which would get parsed as "left". 20 """ 21 test_cases = [(f"\\<{keyname}>", [parsed_keyname]) for keyname, parsed_keyname in _keynames.items()] 22 for test_key, expected_keys in test_cases: 23 with self.subTest(f"{test_key} should be parsed as {expected_keys}"): 24 self.assertEqual(parse_keys(test_key), expected_keys) 25 26 def test_escape_sequences(self): 27 """Ensure that escaping sequences are parsed to their corresponding mapping.""" 28 test_cases = [(f"\\{escape}", [parsed_escape]) for escape, parsed_escape in _escapes.items()] 29 for test_key, expected_keys in test_cases: 30 with self.subTest(f"{test_key} should be parsed as {expected_keys}"): 31 self.assertEqual(parse_keys(test_key), expected_keys) 32 33 def test_control_sequences(self): 34 """Ensure that supported control sequences are parsed successfully.""" 35 keys = ["@", "[", "]", "\\", "^", "_", "\\<space>", "\\<delete>"] 36 keys.extend(string.ascii_letters) 37 test_cases = [(f"\\C-{key}", chr(ord(key) & 0x1F)) for key in []] 38 for test_key, expected_keys in test_cases: 39 with self.subTest(f"{test_key} should be parsed as {expected_keys}"): 40 self.assertEqual(parse_keys(test_key), expected_keys) 41 42 def test_meta_sequences(self): 43 self.assertEqual(parse_keys("\\M-a"), ["\033", "a"]) 44 self.assertEqual(parse_keys("\\M-b"), ["\033", "b"]) 45 self.assertEqual(parse_keys("\\M-c"), ["\033", "c"]) 46 47 def test_combinations(self): 48 self.assertEqual(parse_keys("\\C-a\\n\\<up>"), ["\x01", "\n", "up"]) 49 self.assertEqual(parse_keys("\\M-a\\t\\<down>"), ["\033", "a", "\t", "down"]) 50 51 def test_keyspec_errors(self): 52 cases = [ 53 ("\\Ca", "\\C must be followed by `-'"), 54 ("\\ca", "\\C must be followed by `-'"), 55 ("\\C-\\C-", "doubled \\C-"), 56 ("\\Ma", "\\M must be followed by `-'"), 57 ("\\ma", "\\M must be followed by `-'"), 58 ("\\M-\\M-", "doubled \\M-"), 59 ("\\<left", "unterminated \\<"), 60 ("\\<unsupported>", "unrecognised keyname"), 61 ("\\大", "unknown backslash escape"), 62 ("\\C-\\<backspace>", "\\C- followed by invalid key") 63 ] 64 for test_keys, expected_err in cases: 65 with self.subTest(f"{test_keys} should give error {expected_err}"): 66 with self.assertRaises(KeySpecError) as e: 67 parse_keys(test_keys) 68 self.assertIn(expected_err, str(e.exception)) 69 70 def test_index_errors(self): 71 test_cases = ["\\", "\\C", "\\C-\\C"] 72 for test_keys in test_cases: 73 with self.assertRaises(IndexError): 74 parse_keys(test_keys) 75 76 77class TestCompileKeymap(unittest.TestCase): 78 def test_empty_keymap(self): 79 keymap = {} 80 result = compile_keymap(keymap) 81 self.assertEqual(result, {}) 82 83 def test_single_keymap(self): 84 keymap = {b"a": "action"} 85 result = compile_keymap(keymap) 86 self.assertEqual(result, {b"a": "action"}) 87 88 def test_nested_keymap(self): 89 keymap = {b"a": {b"b": "action"}} 90 result = compile_keymap(keymap) 91 self.assertEqual(result, {b"a": {b"b": "action"}}) 92 93 def test_empty_value(self): 94 keymap = {b"a": {b"": "action"}} 95 result = compile_keymap(keymap) 96 self.assertEqual(result, {b"a": {b"": "action"}}) 97 98 def test_multiple_empty_values(self): 99 keymap = {b"a": {b"": "action1", b"b": "action2"}} 100 result = compile_keymap(keymap) 101 self.assertEqual(result, {b"a": {b"": "action1", b"b": "action2"}}) 102 103 def test_multiple_keymaps(self): 104 keymap = {b"a": {b"b": "action1", b"c": "action2"}} 105 result = compile_keymap(keymap) 106 self.assertEqual(result, {b"a": {b"b": "action1", b"c": "action2"}}) 107 108 def test_nested_multiple_keymaps(self): 109 keymap = {b"a": {b"b": {b"c": "action"}}} 110 result = compile_keymap(keymap) 111 self.assertEqual(result, {b"a": {b"b": {b"c": "action"}}}) 112 113 def test_clashing_definitions(self): 114 km = {b'a': 'c', b'a' + b'b': 'd'} 115 with self.assertRaises(KeySpecError): 116 compile_keymap(km) 117 118 def test_non_bytes_key(self): 119 with self.assertRaises(TypeError): 120 compile_keymap({123: 'a'}) 121