File: test_key_combo.py

package info (click to toggle)
plover 5.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 14,356 kB
  • sloc: python: 21,589; sh: 682; ansic: 25; makefile: 11
file content (160 lines) | stat: -rw-r--r-- 5,047 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import inspect
import itertools

import pytest

from plover.key_combo import parse_key_combo


def generate_combo_tests(test_id, *params, key_name_to_key_code=None):
    yield ("id", test_id)
    if key_name_to_key_code is not None:
        yield ("key_name_to_key_code", key_name_to_key_code)
    for iterables in params:
        iterables = [i if isinstance(i, (tuple, list)) else (i,) for i in iterables]
        if len(iterables) < 2:
            iterables.append(("",))
        for (
            combo_string,
            parse_result,
        ) in itertools.product(*iterables):
            yield (("parse", combo_string, parse_result),)


# Test directives:
# - id TEST_IDENTIFIER
# - key_name_to_key_code KEY_NAME_TO_KEY_CODE_FUNCTION
# - parse COMBO_STRING KEY_EVENTS
KEY_COMBO_TESTS = tuple(
    itertools.chain(
        (("key_name_to_key_code", lambda k: k),),
        # No-op.
        generate_combo_tests(
            "no-op",
            (("", "   "), ""),
        ),
        # Syntax error:
        generate_combo_tests(
            "syntax_error",
            (
                (
                    # - invalid character
                    "Return,",
                    "Return&",
                    "Ret. urn <",
                    "exclam ! foo",
                    "shift[a]",
                    # - unbalanced `)`
                    ") arg",
                    "arg )",
                    "arg())",
                    "arg(x) )",
                    # - unbalanced `(`
                    "test(",
                    "( grr",
                    "foo ( bar",
                    "foo (bar ( ",
                    "foo ((",
                    # - [-+]key() is not valid
                    "+foo ()",
                    "+foo()",
                ),
                SyntaxError,
            ),
        ),
        # Pressing an already pressed key.
        generate_combo_tests(
            "already_pressed",
            (
                (
                    "foo(foo)",
                    "Foo(foO)",
                    "foo(fOo(arg))",
                    "foo(bar(Foo))",
                    "foo(bar(foo(x)))",
                ),
                ValueError,
            ),
        ),
        # Stacking.
        generate_combo_tests(
            "stacking",
            # 1 is not a valid identifier, but still a valid key name.
            ("1", "+1 -1"),
            (("Shift_l", "SHIFT_L"), "+shift_l -shift_l"),
            # Case does not matter.
            (("a", " A "), "+a -a"),
            (("a(b c)", "a ( b c   )"), "+a +b -b +c -c -a"),
            (("a(bc)", " a(  Bc )"), "+a +bc -bc -a"),
            (
                ("a(bc(d)e f(g) h())i j"),
                "+a +bc +d -d -bc +e -e +f +g -g -f +h -h -a +i -i +j -j",
            ),
            (
                ("foo () bar ( foo a b c (d))", "fOo () Bar ( FOO a B c (D))"),
                "+foo -foo +bar +foo -foo +a -a +b -b +c +d -d -c -bar",
            ),
        ),
        # Invalid key name.
        generate_combo_tests(
            "invalid_key",
            ("1 (c) 2 bad 3 (a b c)", ValueError),
            key_name_to_key_code={c: c for c in "123abc"}.get,
        ),
        # Same key code, multiple key names.
        generate_combo_tests(
            "aliasing",
            ("1 exclam", "+10 -10 +10 -10"),
            (("1 ( exclam )", "exclam(1)"), ValueError),
            key_name_to_key_code={"1": "10", "exclam": "10"}.get,
        ),
    )
)


def parametrize(tests):
    key_name_to_key_code = None
    test_id = None
    args = []
    ids = []
    for t in tests:
        if t[0] == "key_name_to_key_code":
            key_name_to_key_code = t[1]
        elif t[0] == "id":
            test_id = t[1]
        else:
            assert key_name_to_key_code is not None
            assert test_id is not None
            args.append((key_name_to_key_code, t))
            ids.append(test_id)
    return pytest.mark.parametrize(
        ("key_name_to_key_code", "instructions"), args, ids=ids
    )


@parametrize(KEY_COMBO_TESTS)
def test_key_combo(key_name_to_key_code, instructions):
    def repr_expected(result):
        assert isinstance(result, str)
        return [s.strip() for s in result.split()]

    def repr_key_events(events):
        assert isinstance(events, list)
        return ["%s%s" % ("+" if pressed else "-", key) for key, pressed in events]

    for action, *args in instructions:
        if action == "parse":
            combo_string, key_events = args
            if inspect.isclass(key_events):
                with pytest.raises(key_events):
                    parse_key_combo(
                        combo_string, key_name_to_key_code=key_name_to_key_code
                    )
            else:
                assert repr_key_events(
                    parse_key_combo(
                        combo_string, key_name_to_key_code=key_name_to_key_code
                    )
                ) == repr_expected(key_events)
        else:
            raise ValueError(args[0])