diff --git a/qutebrowser/keyinput/keyutils.py b/qutebrowser/keyinput/keyutils.py index e456da045..61e3e53b4 100644 --- a/qutebrowser/keyinput/keyutils.py +++ b/qutebrowser/keyinput/keyutils.py @@ -221,7 +221,6 @@ class KeyInfo: modifiers &= ~_MODIFIER_MAP[self.key] elif is_printable(self.key): # "normal" binding - # FIXME Add a test to make sure Tab doesn't become TAB assert len(key_string) == 1 or self.key == Qt.Key_Space, key_string if self.modifiers == Qt.ShiftModifier: return key_string.upper() diff --git a/tests/unit/keyinput/key_data.py b/tests/unit/keyinput/key_data.py index 0164a839b..2f13c8b5e 100644 --- a/tests/unit/keyinput/key_data.py +++ b/tests/unit/keyinput/key_data.py @@ -41,7 +41,7 @@ class Key: """ attribute = attr.ib() - name = attr.ib(None) # default: name == attribute + name = attr.ib(None) text = attr.ib('') uppertext = attr.ib('') member = attr.ib(None) @@ -49,6 +49,8 @@ class Key: def __attrs_post_init__(self): self.member = getattr(Qt, 'Key_' + self.attribute, None) + if self.name is None: + self.name = self.attribute # From enum Key in qt5/qtbase/src/corelib/global/qnamespace.h diff --git a/tests/unit/keyinput/test_keyutils.py b/tests/unit/keyinput/test_keyutils.py index 220d16dc6..7fc6cc12c 100644 --- a/tests/unit/keyinput/test_keyutils.py +++ b/tests/unit/keyinput/test_keyutils.py @@ -28,6 +28,10 @@ from qutebrowser.keyinput import keyutils @pytest.fixture(params=key_data.KEYS, ids=lambda k: k.attribute) def qt_key(request): + """Get all existing keys from key_data.py. + + Keys which don't exist with this Qt version result in skipped tests. + """ key = request.param if key.member is None: pytest.skip("Did not find key {}".format(key.attribute)) @@ -37,10 +41,21 @@ def qt_key(request): @pytest.fixture(params=[key for key in key_data.KEYS if key.qtest], ids=lambda k: k.attribute) def qtest_key(request): + """Get keys from key_data.py which can be used with QTest.""" return request.param -class KeyTestWidget(QWidget): +def test_key_data(): + """Make sure all possible keys are in key_data.KEYS.""" + key_names = {name[len("Key_"):] + for name, value in sorted(vars(Qt).items()) + if isinstance(value, Qt.Key)} + key_data_names = {key.attribute for key in sorted(key_data.KEYS)} + diff = key_names - key_data_names + assert not diff + + +class KeyTesterWidget(QWidget): """Widget to get the text of QKeyPressEvents. @@ -59,35 +74,42 @@ class KeyTestWidget(QWidget): self.got_text.emit() -class TestKeyText: +class TestKeyInfoText: @pytest.mark.parametrize('upper', [False, True]) - def test_key_text(self, qt_key, upper): + def test_text(self, qt_key, upper): + """Test KeyInfo.text() with all possible keys. + + See key_data.py for inputs and expected values. + """ modifiers = Qt.ShiftModifier if upper else Qt.KeyboardModifiers() info = keyutils.KeyInfo(qt_key.member, modifiers=modifiers) expected = qt_key.uppertext if upper else qt_key.text assert info.text() == expected @pytest.fixture - def key_test(self, qtbot): - w = KeyTestWidget() + def key_tester(self, qtbot): + w = KeyTesterWidget() qtbot.add_widget(w) return w - def test_key_test_qtest(self, qtest_key, qtbot, key_test): - with qtbot.wait_signal(key_test.got_text): - qtbot.keyPress(key_test, qtest_key.member) + def test_text_qtest(self, qtest_key, qtbot, key_tester): + """Make sure KeyInfo.text() lines up with QTest::keyToAscii. + + See key_data.py for inputs and expected values. + """ + with qtbot.wait_signal(key_tester.got_text): + qtbot.keyPress(key_tester, qtest_key.member) info = keyutils.KeyInfo(qtest_key.member, modifiers=Qt.KeyboardModifiers()) - assert info.text() == key_test.text.lower() + assert info.text() == key_tester.text.lower() class TestKeyToString: def test_to_string(self, qt_key): - name = qt_key.attribute if qt_key.name is None else qt_key.name - assert keyutils._key_to_string(qt_key.member) == name + assert keyutils._key_to_string(qt_key.member) == qt_key.name def test_missing(self, monkeypatch): monkeypatch.delattr(keyutils.Qt, 'Key_Blue') @@ -95,57 +117,24 @@ class TestKeyToString: # want to know if the mapping still behaves properly. assert keyutils._key_to_string(Qt.Key_A) == 'A' - def test_all(self): - """Make sure all possible keys are in key_data.KEYS.""" - key_names = {name[len("Key_"):] - for name, value in sorted(vars(Qt).items()) - if isinstance(value, Qt.Key)} - key_data_names = {key.attribute for key in sorted(key_data.KEYS)} - diff = key_names - key_data_names - assert not diff +@pytest.mark.parametrize('key, modifiers, expected', [ + (Qt.Key_A, Qt.NoModifier, 'a'), + (Qt.Key_A, Qt.ShiftModifier, 'A'), -class TestKeyEventToString: + (Qt.Key_Tab, Qt.ShiftModifier, ''), + (Qt.Key_A, Qt.ControlModifier, ''), + (Qt.Key_A, Qt.ControlModifier | Qt.ShiftModifier, ''), + (Qt.Key_A, + Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier | Qt.ShiftModifier, + ''), - """Test keyevent_to_string.""" + (Qt.Key_Shift, Qt.ShiftModifier, ''), + (Qt.Key_Shift, Qt.ShiftModifier | Qt.ControlModifier, ''), +]) +def test_key_info_str(key, modifiers, expected): + assert str(keyutils.KeyInfo(key, modifiers)) == expected - def test_only_control(self, fake_keyevent_factory): - """Test keyeevent when only control is pressed.""" - evt = fake_keyevent_factory(key=Qt.Key_Control, - modifiers=Qt.ControlModifier) - assert str(keyutils.KeyInfo.from_event(evt)) == '' - - def test_only_key(self, fake_keyevent_factory): - """Test with a simple key pressed.""" - evt = fake_keyevent_factory(key=Qt.Key_A) - assert str(keyutils.KeyInfo.from_event(evt)) == 'a' - - def test_key_and_modifier(self, fake_keyevent_factory): - """Test with key and modifier pressed.""" - evt = fake_keyevent_factory(key=Qt.Key_A, modifiers=Qt.ControlModifier) - expected = '' if utils.is_mac else '' - assert str(keyutils.KeyInfo.from_event(evt)) == expected - - def test_key_and_modifiers(self, fake_keyevent_factory): - """Test with key and multiple modifiers pressed.""" - evt = fake_keyevent_factory( - key=Qt.Key_A, modifiers=(Qt.ControlModifier | Qt.AltModifier | - Qt.MetaModifier | Qt.ShiftModifier)) - s = str(keyutils.KeyInfo.from_event(evt)) - assert s == '' - - def test_modifier_key(self, fake_keyevent_factory): - evt = fake_keyevent_factory(key=Qt.Key_Shift, - modifiers=Qt.ShiftModifier) - s = str(keyutils.KeyInfo.from_event(evt)) - assert s == '' - - def test_modifier_key_with_modifiers(self, fake_keyevent_factory): - evt = fake_keyevent_factory(key=Qt.Key_Shift, - modifiers=(Qt.ShiftModifier | - Qt.ControlModifier)) - s = str(keyutils.KeyInfo.from_event(evt)) - assert s == '' @pytest.mark.parametrize('keystr, expected', [ ('', keyutils.KeySequence(Qt.ControlModifier | Qt.Key_X)), @@ -170,18 +159,17 @@ def test_parse(keystr, expected): @pytest.mark.parametrize('orig, normalized', [ - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', ''), - ('', '') + ('', ''), + ('', ''), + ('', ''), + ('', ''), + ('', ''), + ('', ''), + ('', ''), + ('', '') ]) def test_normalize_keystr(orig, normalized): - expected = keyutils.KeySequence.parse(normalized) - assert keyutils.KeySequence.parse(orig) == expected + assert str(keyutils.KeySequence.parse(orig)) == normalized @pytest.mark.parametrize('key, printable', [ @@ -194,7 +182,7 @@ def test_normalize_keystr(orig, normalized): (Qt.Key_Enter, False), (Qt.Key_X | Qt.ControlModifier, False), # Wrong usage - (Qt.Key_Space, True), + (Qt.Key_Space, True), # FIXME broken with upper/lower! (Qt.Key_ydiaeresis, True), (Qt.Key_X, True), ])