1
+ import string
1
2
import unittest
2
3
3
- from _pyrepl .keymap import parse_keys , compile_keymap
4
+ from _pyrepl .keymap import _keynames , _escapes , parse_keys , compile_keymap , KeySpecError
4
5
5
6
6
7
class TestParseKeys (unittest .TestCase ):
7
8
def test_single_character (self ):
8
- self .assertEqual (parse_keys ("a" ), ["a" ])
9
- self .assertEqual (parse_keys ("b" ), ["b" ])
10
- self .assertEqual (parse_keys ("1" ), ["1" ])
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 )
11
25
12
26
def test_escape_sequences (self ):
13
- self . assertEqual ( parse_keys ( " \\ n" ), [ " \n " ])
14
- self . assertEqual ( parse_keys ( "\\ t" ) , [" \t " ])
15
- self . assertEqual ( parse_keys ( " \\ \\ " ), [ " \\ " ])
16
- self .assertEqual ( parse_keys ( " \\ '" ), [ "'" ])
17
- self .assertEqual (parse_keys (' \\ "' ), [ '"' ] )
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 )
18
32
19
33
def test_control_sequences (self ):
20
- self .assertEqual (parse_keys ("\\ C-a" ), ["\x01 " ])
21
- self .assertEqual (parse_keys ("\\ C-b" ), ["\x02 " ])
22
- self .assertEqual (parse_keys ("\\ C-c" ), ["\x03 " ])
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 )
23
41
24
42
def test_meta_sequences (self ):
25
43
self .assertEqual (parse_keys ("\\ M-a" ), ["\033 " , "a" ])
26
44
self .assertEqual (parse_keys ("\\ M-b" ), ["\033 " , "b" ])
27
45
self .assertEqual (parse_keys ("\\ M-c" ), ["\033 " , "c" ])
28
46
29
- def test_keynames (self ):
30
- self .assertEqual (parse_keys ("\\ <up>" ), ["up" ])
31
- self .assertEqual (parse_keys ("\\ <down>" ), ["down" ])
32
- self .assertEqual (parse_keys ("\\ <left>" ), ["left" ])
33
- self .assertEqual (parse_keys ("\\ <right>" ), ["right" ])
34
-
35
47
def test_combinations (self ):
36
48
self .assertEqual (parse_keys ("\\ C-a\\ n\\ <up>" ), ["\x01 " , "\n " , "up" ])
37
49
self .assertEqual (parse_keys ("\\ M-a\\ t\\ <down>" ), ["\033 " , "a" , "\t " , "down" ])
38
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
+
39
76
40
77
class TestCompileKeymap (unittest .TestCase ):
41
78
def test_empty_keymap (self ):
@@ -72,3 +109,12 @@ def test_nested_multiple_keymaps(self):
72
109
keymap = {b"a" : {b"b" : {b"c" : "action" }}}
73
110
result = compile_keymap (keymap )
74
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' })
0 commit comments