qutebrowser/tests/unit/keyinput/test_keyutils.py

202 lines
6.7 KiB
Python
Raw Normal View History

2017-12-29 01:41:55 +01:00
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
2018-02-27 14:16:59 +01:00
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
2017-12-29 01:41:55 +01:00
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
import pytest
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtWidgets import QWidget
2017-12-29 01:41:55 +01:00
2018-02-28 09:03:47 +01:00
from tests.unit.keyinput import key_data
2018-02-27 09:07:20 +01:00
from qutebrowser.utils import utils
2017-12-29 01:41:55 +01:00
from qutebrowser.keyinput import keyutils
2018-02-28 10:41:09 +01:00
@pytest.fixture(params=key_data.KEYS, ids=lambda k: k.attribute)
2018-02-28 09:03:47 +01:00
def qt_key(request):
2018-03-03 22:47:19 +01:00
"""Get all existing keys from key_data.py.
Keys which don't exist with this Qt version result in skipped tests.
"""
2018-02-28 09:51:19 +01:00
key = request.param
if key.member is None:
2018-02-28 09:51:19 +01:00
pytest.skip("Did not find key {}".format(key.attribute))
2018-02-28 09:03:47 +01:00
return key
2017-12-29 01:41:55 +01:00
@pytest.fixture(params=[key for key in key_data.KEYS if key.qtest],
ids=lambda k: k.attribute)
def qtest_key(request):
2018-03-03 22:47:19 +01:00
"""Get keys from key_data.py which can be used with QTest."""
return request.param
2018-02-28 10:59:01 +01:00
2018-03-03 22:47:19 +01:00
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.
This is done so we can check QTest::keyToAscii (qasciikey.cpp) as we can't
call that directly, only via QTest::keyPress.
"""
got_text = pyqtSignal()
2018-03-01 08:56:39 +01:00
def __init__(self, parent=None):
super().__init__(parent)
self.text = None
def keyPressEvent(self, e):
self.text = e.text()
self.got_text.emit()
2018-03-03 22:47:19 +01:00
class TestKeyInfoText:
@pytest.mark.parametrize('upper', [False, True])
2018-03-03 22:47:19 +01:00
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
2018-03-03 22:47:19 +01:00
def key_tester(self, qtbot):
w = KeyTesterWidget()
qtbot.add_widget(w)
return w
2018-03-03 22:47:19 +01:00
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())
2018-03-03 22:47:19 +01:00
assert info.text() == key_tester.text.lower()
2018-02-28 09:03:47 +01:00
class TestKeyToString:
2017-12-29 01:41:55 +01:00
2018-02-28 10:21:02 +01:00
def test_to_string(self, qt_key):
2018-03-03 22:47:19 +01:00
assert keyutils._key_to_string(qt_key.member) == qt_key.name
2017-12-29 01:41:55 +01:00
def test_missing(self, monkeypatch):
monkeypatch.delattr(keyutils.Qt, 'Key_Blue')
# We don't want to test the key which is actually missing - we only
# want to know if the mapping still behaves properly.
2018-02-27 22:21:35 +01:00
assert keyutils._key_to_string(Qt.Key_A) == 'A'
2017-12-29 01:41:55 +01:00
2018-03-03 22:47:19 +01:00
@pytest.mark.parametrize('key, modifiers, expected', [
(Qt.Key_A, Qt.NoModifier, 'a'),
(Qt.Key_A, Qt.ShiftModifier, 'A'),
(Qt.Key_Space, Qt.NoModifier, '<Space>'),
(Qt.Key_Space, Qt.ShiftModifier, '<Shift+Space>'),
2018-03-03 22:47:19 +01:00
(Qt.Key_Tab, Qt.ShiftModifier, '<Shift+Tab>'),
(Qt.Key_A, Qt.ControlModifier, '<Ctrl+a>'),
(Qt.Key_A, Qt.ControlModifier | Qt.ShiftModifier, '<Ctrl+Shift+a>'),
(Qt.Key_A,
Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier | Qt.ShiftModifier,
'<Meta+Ctrl+Alt+Shift+a>'),
(Qt.Key_Shift, Qt.ShiftModifier, '<Shift>'),
(Qt.Key_Shift, Qt.ShiftModifier | Qt.ControlModifier, '<Ctrl+Shift>'),
])
def test_key_info_str(key, modifiers, expected):
assert str(keyutils.KeyInfo(key, modifiers)) == expected
2017-12-29 01:41:55 +01:00
@pytest.mark.parametrize('keystr, expected', [
2017-12-29 13:23:38 +01:00
('<Control-x>', keyutils.KeySequence(Qt.ControlModifier | Qt.Key_X)),
('<Meta-x>', keyutils.KeySequence(Qt.MetaModifier | Qt.Key_X)),
2017-12-29 01:41:55 +01:00
('<Ctrl-Alt-y>',
2017-12-29 13:23:38 +01:00
keyutils.KeySequence(Qt.ControlModifier | Qt.AltModifier | Qt.Key_Y)),
('x', keyutils.KeySequence(Qt.Key_X)),
('X', keyutils.KeySequence(Qt.ShiftModifier | Qt.Key_X)),
('<Escape>', keyutils.KeySequence(Qt.Key_Escape)),
('xyz', keyutils.KeySequence(Qt.Key_X, Qt.Key_Y, Qt.Key_Z)),
('<Control-x><Meta-y>', keyutils.KeySequence(Qt.ControlModifier | Qt.Key_X,
Qt.MetaModifier | Qt.Key_Y)),
2018-02-28 12:57:25 +01:00
('<blub>', keyutils.KeyParseError),
('\U00010000', keyutils.KeyParseError),
2017-12-29 01:41:55 +01:00
])
2017-12-29 13:23:38 +01:00
def test_parse(keystr, expected):
2017-12-29 01:41:55 +01:00
if expected is keyutils.KeyParseError:
with pytest.raises(keyutils.KeyParseError):
2018-02-27 09:07:20 +01:00
keyutils.KeySequence.parse(keystr)
2017-12-29 01:41:55 +01:00
else:
2018-02-27 09:07:20 +01:00
assert keyutils.KeySequence.parse(keystr) == expected
@pytest.mark.parametrize('orig, normalized', [
2018-03-03 22:47:19 +01:00
('<Control+x>', '<Ctrl+x>'),
('<Windows+x>', '<Meta+x>'),
('<Mod1+x>', '<Alt+x>'),
('<Mod4+x>', '<Meta+x>'),
('<Control-->', '<Ctrl+->'),
('<Windows++>', '<Meta++>'),
('<ctrl-x>', '<Ctrl+x>'),
('<control+x>', '<Ctrl+x>')
2017-12-29 01:41:55 +01:00
])
2018-02-27 09:07:20 +01:00
def test_normalize_keystr(orig, normalized):
2018-03-03 22:47:19 +01:00
assert str(keyutils.KeySequence.parse(orig)) == normalized
2018-03-01 00:34:33 +01:00
@pytest.mark.parametrize('key, printable', [
(Qt.Key_Control, False),
(Qt.Key_Escape, False),
(Qt.Key_Tab, False),
2018-03-02 13:44:59 +01:00
(Qt.Key_Backtab, False),
(Qt.Key_Backspace, False),
(Qt.Key_Return, False),
(Qt.Key_Enter, False),
(Qt.Key_Space, False),
2018-03-02 13:44:59 +01:00
(Qt.Key_X | Qt.ControlModifier, False), # Wrong usage
(Qt.Key_ydiaeresis, True),
2018-03-02 13:44:59 +01:00
(Qt.Key_X, True),
2018-03-01 00:34:33 +01:00
])
def test_is_printable(key, printable):
assert keyutils.is_printable(key) == printable
@pytest.mark.parametrize('key, ismodifier', [
(Qt.Key_Control, True),
(Qt.Key_X, False),
(Qt.Key_Super_L, False), # Modifier but not in _MODIFIER_MAP
])
def test_is_modifier_key(key, ismodifier):
assert keyutils.is_modifier_key(key) == ismodifier