Split config commands off to their own file.
This commit is contained in:
parent
32d529b54e
commit
a8fc561707
@ -23,13 +23,11 @@ import copy
|
||||
import contextlib
|
||||
import functools
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QUrl
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject
|
||||
|
||||
from qutebrowser.config import configdata, configexc, configtypes
|
||||
from qutebrowser.utils import utils, objreg, message, log, jinja
|
||||
from qutebrowser.config import configdata, configexc
|
||||
from qutebrowser.utils import utils, log, jinja
|
||||
from qutebrowser.misc import objects
|
||||
from qutebrowser.commands import cmdexc, cmdutils
|
||||
from qutebrowser.completion.models import configmodel
|
||||
|
||||
# An easy way to access the config from other code via config.val.foo
|
||||
val = None
|
||||
@ -205,148 +203,6 @@ class KeyConfig:
|
||||
self._config.update_mutables(save_yaml=save_yaml)
|
||||
|
||||
|
||||
class ConfigCommands:
|
||||
|
||||
"""qutebrowser commands related to the configuration."""
|
||||
|
||||
def __init__(self, config, keyconfig):
|
||||
self._config = config
|
||||
self._keyconfig = keyconfig
|
||||
|
||||
@cmdutils.register(instance='config-commands', star_args_optional=True)
|
||||
@cmdutils.argument('option', completion=configmodel.option)
|
||||
@cmdutils.argument('values', completion=configmodel.value)
|
||||
@cmdutils.argument('win_id', win_id=True)
|
||||
def set(self, win_id, option=None, *values, temp=False, print_=False):
|
||||
"""Set an option.
|
||||
|
||||
If the option name ends with '?', the value of the option is shown
|
||||
instead.
|
||||
|
||||
If the option name ends with '!' and it is a boolean value, toggle it.
|
||||
|
||||
Args:
|
||||
option: The name of the option.
|
||||
values: The value to set, or the values to cycle through.
|
||||
temp: Set value temporarily until qutebrowser is closed.
|
||||
print_: Print the value after setting.
|
||||
"""
|
||||
if option is None:
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
tabbed_browser.openurl(QUrl('qute://settings'), newtab=False)
|
||||
return
|
||||
|
||||
if option.endswith('?') and option != '?':
|
||||
self._print_value(option[:-1])
|
||||
return
|
||||
|
||||
with self._handle_config_error():
|
||||
if option.endswith('!') and option != '!' and not values:
|
||||
# Handle inversion as special cases of the cycle code path
|
||||
option = option[:-1]
|
||||
opt = self._config.get_opt(option)
|
||||
if isinstance(opt.typ, configtypes.Bool):
|
||||
values = ['false', 'true']
|
||||
else:
|
||||
raise cmdexc.CommandError(
|
||||
"set: Can't toggle non-bool setting {}".format(option))
|
||||
elif not values:
|
||||
raise cmdexc.CommandError("set: The following arguments "
|
||||
"are required: value")
|
||||
self._set_next(option, values, temp=temp)
|
||||
|
||||
if print_:
|
||||
self._print_value(option)
|
||||
|
||||
def _print_value(self, option):
|
||||
"""Print the value of the given option."""
|
||||
with self._handle_config_error():
|
||||
value = self._config.get_str(option)
|
||||
message.info("{} = {}".format(option, value))
|
||||
|
||||
def _set_next(self, option, values, *, temp):
|
||||
"""Set the next value out of a list of values."""
|
||||
if len(values) == 1:
|
||||
# If we have only one value, just set it directly (avoid
|
||||
# breaking stuff like aliases or other pseudo-settings)
|
||||
self._config.set_str(option, values[0], save_yaml=not temp)
|
||||
return
|
||||
|
||||
# Use the next valid value from values, or the first if the current
|
||||
# value does not appear in the list
|
||||
old_value = self._config.get_obj(option, mutable=False)
|
||||
opt = self._config.get_opt(option)
|
||||
values = [opt.typ.from_str(val) for val in values]
|
||||
|
||||
try:
|
||||
idx = values.index(old_value)
|
||||
idx = (idx + 1) % len(values)
|
||||
value = values[idx]
|
||||
except ValueError:
|
||||
value = values[0]
|
||||
self._config.set_obj(option, value, save_yaml=not temp)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _handle_config_error(self):
|
||||
"""Catch errors in set_command and raise CommandError."""
|
||||
try:
|
||||
yield
|
||||
except configexc.Error as e:
|
||||
raise cmdexc.CommandError("set: {}".format(e))
|
||||
|
||||
@cmdutils.register(instance='config-commands', maxsplit=1,
|
||||
no_cmd_split=True, no_replace_variables=True)
|
||||
@cmdutils.argument('command', completion=configmodel.bind)
|
||||
def bind(self, key, command=None, *, mode='normal', force=False):
|
||||
"""Bind a key to a command.
|
||||
|
||||
Args:
|
||||
key: The keychain or special key (inside `<...>`) to bind.
|
||||
command: The command to execute, with optional args, or None to
|
||||
print the current binding.
|
||||
mode: A comma-separated list of modes to bind the key in
|
||||
(default: `normal`). See `:help bindings.commands` for the
|
||||
available modes.
|
||||
force: Rebind the key if it is already bound.
|
||||
"""
|
||||
if command is None:
|
||||
if utils.is_special_key(key):
|
||||
# self._keyconfig.get_command does this, but we also need it
|
||||
# normalized for the output below
|
||||
key = utils.normalize_keystr(key)
|
||||
cmd = self._keyconfig.get_command(key, mode)
|
||||
if cmd is None:
|
||||
message.info("{} is unbound in {} mode".format(key, mode))
|
||||
else:
|
||||
message.info("{} is bound to '{}' in {} mode".format(
|
||||
key, cmd, mode))
|
||||
return
|
||||
|
||||
try:
|
||||
self._keyconfig.bind(key, command, mode=mode, force=force,
|
||||
save_yaml=True)
|
||||
except configexc.DuplicateKeyError as e:
|
||||
raise cmdexc.CommandError("bind: {} - use --force to override!"
|
||||
.format(e))
|
||||
except configexc.KeybindingError as e:
|
||||
raise cmdexc.CommandError("bind: {}".format(e))
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
def unbind(self, key, *, mode='normal'):
|
||||
"""Unbind a keychain.
|
||||
|
||||
Args:
|
||||
key: The keychain or special key (inside <...>) to unbind.
|
||||
mode: A mode to unbind the key in (default: `normal`).
|
||||
See `:help bindings.commands` for the available modes.
|
||||
"""
|
||||
try:
|
||||
self._keyconfig.unbind(key, mode=mode, save_yaml=True)
|
||||
except configexc.KeybindingError as e:
|
||||
raise cmdexc.CommandError('unbind: {}'.format(e))
|
||||
|
||||
|
||||
class Config(QObject):
|
||||
|
||||
"""Main config object.
|
||||
|
171
qutebrowser/config/configcommands.py
Normal file
171
qutebrowser/config/configcommands.py
Normal file
@ -0,0 +1,171 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
"""Commands related to the configuration."""
|
||||
|
||||
import contextlib
|
||||
|
||||
from PyQt5.QtCore import QUrl
|
||||
|
||||
from qutebrowser.commands import cmdexc, cmdutils
|
||||
from qutebrowser.completion.models import configmodel
|
||||
from qutebrowser.utils import objreg, utils, message
|
||||
from qutebrowser.config import configtypes, configexc
|
||||
|
||||
|
||||
class ConfigCommands:
|
||||
|
||||
"""qutebrowser commands related to the configuration."""
|
||||
|
||||
def __init__(self, config, keyconfig):
|
||||
self._config = config
|
||||
self._keyconfig = keyconfig
|
||||
|
||||
@cmdutils.register(instance='config-commands', star_args_optional=True)
|
||||
@cmdutils.argument('option', completion=configmodel.option)
|
||||
@cmdutils.argument('values', completion=configmodel.value)
|
||||
@cmdutils.argument('win_id', win_id=True)
|
||||
def set(self, win_id, option=None, *values, temp=False, print_=False):
|
||||
"""Set an option.
|
||||
|
||||
If the option name ends with '?', the value of the option is shown
|
||||
instead.
|
||||
|
||||
If the option name ends with '!' and it is a boolean value, toggle it.
|
||||
|
||||
Args:
|
||||
option: The name of the option.
|
||||
values: The value to set, or the values to cycle through.
|
||||
temp: Set value temporarily until qutebrowser is closed.
|
||||
print_: Print the value after setting.
|
||||
"""
|
||||
if option is None:
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
tabbed_browser.openurl(QUrl('qute://settings'), newtab=False)
|
||||
return
|
||||
|
||||
if option.endswith('?') and option != '?':
|
||||
self._print_value(option[:-1])
|
||||
return
|
||||
|
||||
with self._handle_config_error():
|
||||
if option.endswith('!') and option != '!' and not values:
|
||||
# Handle inversion as special cases of the cycle code path
|
||||
option = option[:-1]
|
||||
opt = self._config.get_opt(option)
|
||||
if isinstance(opt.typ, configtypes.Bool):
|
||||
values = ['false', 'true']
|
||||
else:
|
||||
raise cmdexc.CommandError(
|
||||
"set: Can't toggle non-bool setting {}".format(option))
|
||||
elif not values:
|
||||
raise cmdexc.CommandError("set: The following arguments "
|
||||
"are required: value")
|
||||
self._set_next(option, values, temp=temp)
|
||||
|
||||
if print_:
|
||||
self._print_value(option)
|
||||
|
||||
def _print_value(self, option):
|
||||
"""Print the value of the given option."""
|
||||
with self._handle_config_error():
|
||||
value = self._config.get_str(option)
|
||||
message.info("{} = {}".format(option, value))
|
||||
|
||||
def _set_next(self, option, values, *, temp):
|
||||
"""Set the next value out of a list of values."""
|
||||
if len(values) == 1:
|
||||
# If we have only one value, just set it directly (avoid
|
||||
# breaking stuff like aliases or other pseudo-settings)
|
||||
self._config.set_str(option, values[0], save_yaml=not temp)
|
||||
return
|
||||
|
||||
# Use the next valid value from values, or the first if the current
|
||||
# value does not appear in the list
|
||||
old_value = self._config.get_obj(option, mutable=False)
|
||||
opt = self._config.get_opt(option)
|
||||
values = [opt.typ.from_str(val) for val in values]
|
||||
|
||||
try:
|
||||
idx = values.index(old_value)
|
||||
idx = (idx + 1) % len(values)
|
||||
value = values[idx]
|
||||
except ValueError:
|
||||
value = values[0]
|
||||
self._config.set_obj(option, value, save_yaml=not temp)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _handle_config_error(self):
|
||||
"""Catch errors in set_command and raise CommandError."""
|
||||
try:
|
||||
yield
|
||||
except configexc.Error as e:
|
||||
raise cmdexc.CommandError("set: {}".format(e))
|
||||
|
||||
@cmdutils.register(instance='config-commands', maxsplit=1,
|
||||
no_cmd_split=True, no_replace_variables=True)
|
||||
@cmdutils.argument('command', completion=configmodel.bind)
|
||||
def bind(self, key, command=None, *, mode='normal', force=False):
|
||||
"""Bind a key to a command.
|
||||
|
||||
Args:
|
||||
key: The keychain or special key (inside `<...>`) to bind.
|
||||
command: The command to execute, with optional args, or None to
|
||||
print the current binding.
|
||||
mode: A comma-separated list of modes to bind the key in
|
||||
(default: `normal`). See `:help bindings.commands` for the
|
||||
available modes.
|
||||
force: Rebind the key if it is already bound.
|
||||
"""
|
||||
if command is None:
|
||||
if utils.is_special_key(key):
|
||||
# self._keyconfig.get_command does this, but we also need it
|
||||
# normalized for the output below
|
||||
key = utils.normalize_keystr(key)
|
||||
cmd = self._keyconfig.get_command(key, mode)
|
||||
if cmd is None:
|
||||
message.info("{} is unbound in {} mode".format(key, mode))
|
||||
else:
|
||||
message.info("{} is bound to '{}' in {} mode".format(
|
||||
key, cmd, mode))
|
||||
return
|
||||
|
||||
try:
|
||||
self._keyconfig.bind(key, command, mode=mode, force=force,
|
||||
save_yaml=True)
|
||||
except configexc.DuplicateKeyError as e:
|
||||
raise cmdexc.CommandError("bind: {} - use --force to override!"
|
||||
.format(e))
|
||||
except configexc.KeybindingError as e:
|
||||
raise cmdexc.CommandError("bind: {}".format(e))
|
||||
|
||||
@cmdutils.register(instance='config-commands')
|
||||
def unbind(self, key, *, mode='normal'):
|
||||
"""Unbind a keychain.
|
||||
|
||||
Args:
|
||||
key: The keychain or special key (inside <...>) to unbind.
|
||||
mode: A mode to unbind the key in (default: `normal`).
|
||||
See `:help bindings.commands` for the available modes.
|
||||
"""
|
||||
try:
|
||||
self._keyconfig.unbind(key, mode=mode, save_yaml=True)
|
||||
except configexc.KeybindingError as e:
|
||||
raise cmdexc.CommandError('unbind: {}'.format(e))
|
@ -25,7 +25,7 @@ import sys
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
from qutebrowser.config import (config, configdata, configfiles, configtypes,
|
||||
configexc)
|
||||
configexc, configcommands)
|
||||
from qutebrowser.utils import objreg, usertypes, log, standarddir, message
|
||||
from qutebrowser.misc import msgbox, objects
|
||||
|
||||
@ -50,8 +50,8 @@ def early_init(args):
|
||||
|
||||
configtypes.Font.monospace_fonts = config.val.fonts.monospace
|
||||
|
||||
config_commands = config.ConfigCommands(config.instance,
|
||||
config.key_instance)
|
||||
config_commands = configcommands.ConfigCommands(
|
||||
config.instance, config.key_instance)
|
||||
objreg.register('config-commands', config_commands)
|
||||
|
||||
config_file = os.path.join(standarddir.config(), 'config.py')
|
||||
|
@ -143,6 +143,8 @@ PERFECT_FILES = [
|
||||
'config/configtypes.py'),
|
||||
('tests/unit/config/test_configinit.py',
|
||||
'config/configinit.py'),
|
||||
('tests/unit/config/test_configcommands.py',
|
||||
'config/configcommands.py'),
|
||||
|
||||
('tests/unit/utils/test_qtutils.py',
|
||||
'utils/qtutils.py'),
|
||||
|
29
tests/unit/config/conftest.py
Normal file
29
tests/unit/config/conftest.py
Normal file
@ -0,0 +1,29 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
# Copyright 2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
|
||||
# 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/>.
|
||||
|
||||
"""Fixtures needed in various config test files."""
|
||||
|
||||
import pytest
|
||||
|
||||
from qutebrowser.config import config
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def keyconf(config_stub):
|
||||
config_stub.val.aliases = {}
|
||||
return config.KeyConfig(config_stub)
|
@ -22,12 +22,11 @@ import copy
|
||||
import types
|
||||
|
||||
import pytest
|
||||
from PyQt5.QtCore import QObject, QUrl
|
||||
from PyQt5.QtCore import QObject
|
||||
from PyQt5.QtGui import QColor
|
||||
|
||||
from qutebrowser.commands import cmdexc
|
||||
from qutebrowser.config import config, configdata, configexc
|
||||
from qutebrowser.utils import objreg, usertypes
|
||||
from qutebrowser.utils import usertypes
|
||||
from qutebrowser.misc import objects
|
||||
|
||||
|
||||
@ -38,12 +37,6 @@ def configdata_init():
|
||||
configdata.init()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def keyconf(config_stub):
|
||||
config_stub.val.aliases = {}
|
||||
return config.KeyConfig(config_stub)
|
||||
|
||||
|
||||
class TestChangeFilter:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@ -262,342 +255,6 @@ class TestKeyConfig:
|
||||
keyconf.unbind('foobar', mode='normal')
|
||||
|
||||
|
||||
class TestSetConfigCommand:
|
||||
|
||||
"""Tests for :set."""
|
||||
|
||||
@pytest.fixture
|
||||
def commands(self, config_stub, keyconf):
|
||||
return config.ConfigCommands(config_stub, keyconf)
|
||||
|
||||
@pytest.fixture
|
||||
def tabbed_browser(self, stubs, win_registry):
|
||||
tb = stubs.TabbedBrowserStub()
|
||||
objreg.register('tabbed-browser', tb, scope='window', window=0)
|
||||
yield tb
|
||||
objreg.delete('tabbed-browser', scope='window', window=0)
|
||||
|
||||
def test_set_no_args(self, commands, tabbed_browser):
|
||||
"""Run ':set'.
|
||||
|
||||
Should open qute://settings."""
|
||||
commands.set(win_id=0)
|
||||
assert tabbed_browser.opened_url == QUrl('qute://settings')
|
||||
|
||||
def test_get(self, config_stub, commands, message_mock):
|
||||
"""Run ':set url.auto_search?'.
|
||||
|
||||
Should show the value.
|
||||
"""
|
||||
config_stub.val.url.auto_search = 'never'
|
||||
commands.set(win_id=0, option='url.auto_search?')
|
||||
msg = message_mock.getmsg(usertypes.MessageLevel.info)
|
||||
assert msg.text == 'url.auto_search = never'
|
||||
|
||||
@pytest.mark.parametrize('temp', [True, False])
|
||||
@pytest.mark.parametrize('option, old_value, inp, new_value', [
|
||||
('url.auto_search', 'naive', 'dns', 'dns'),
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/2962
|
||||
('editor.command', ['gvim', '-f', '{}'], '[emacs, "{}"]',
|
||||
['emacs', '{}']),
|
||||
])
|
||||
def test_set_simple(self, monkeypatch, commands, config_stub,
|
||||
temp, option, old_value, inp, new_value):
|
||||
"""Run ':set [-t] option value'.
|
||||
|
||||
Should set the setting accordingly.
|
||||
"""
|
||||
monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebKit)
|
||||
assert config_stub.get(option) == old_value
|
||||
|
||||
commands.set(0, option, inp, temp=temp)
|
||||
|
||||
assert config_stub.get(option) == new_value
|
||||
|
||||
if temp:
|
||||
assert option not in config_stub._yaml
|
||||
else:
|
||||
assert config_stub._yaml[option] == new_value
|
||||
|
||||
@pytest.mark.parametrize('temp', [True, False])
|
||||
def test_set_temp_override(self, commands, config_stub, temp):
|
||||
"""Invoking :set twice.
|
||||
|
||||
:set url.auto_search dns
|
||||
:set -t url.auto_search never
|
||||
|
||||
Should set the setting accordingly.
|
||||
"""
|
||||
assert config_stub.val.url.auto_search == 'naive'
|
||||
commands.set(0, 'url.auto_search', 'dns')
|
||||
commands.set(0, 'url.auto_search', 'never', temp=True)
|
||||
|
||||
assert config_stub.val.url.auto_search == 'never'
|
||||
assert config_stub._yaml['url.auto_search'] == 'dns'
|
||||
|
||||
def test_set_print(self, config_stub, commands, message_mock):
|
||||
"""Run ':set -p url.auto_search never'.
|
||||
|
||||
Should set show the value.
|
||||
"""
|
||||
assert config_stub.val.url.auto_search == 'naive'
|
||||
commands.set(0, 'url.auto_search', 'dns', print_=True)
|
||||
|
||||
assert config_stub.val.url.auto_search == 'dns'
|
||||
msg = message_mock.getmsg(usertypes.MessageLevel.info)
|
||||
assert msg.text == 'url.auto_search = dns'
|
||||
|
||||
def test_set_toggle(self, commands, config_stub):
|
||||
"""Run ':set auto_save.session!'.
|
||||
|
||||
Should toggle the value.
|
||||
"""
|
||||
assert not config_stub.val.auto_save.session
|
||||
commands.set(0, 'auto_save.session!')
|
||||
assert config_stub.val.auto_save.session
|
||||
assert config_stub._yaml['auto_save.session']
|
||||
|
||||
def test_set_toggle_nonbool(self, commands, config_stub):
|
||||
"""Run ':set url.auto_search!'.
|
||||
|
||||
Should show an error
|
||||
"""
|
||||
assert config_stub.val.url.auto_search == 'naive'
|
||||
with pytest.raises(cmdexc.CommandError, match="set: Can't toggle "
|
||||
"non-bool setting url.auto_search"):
|
||||
commands.set(0, 'url.auto_search!')
|
||||
assert config_stub.val.url.auto_search == 'naive'
|
||||
|
||||
def test_set_toggle_print(self, commands, config_stub, message_mock):
|
||||
"""Run ':set -p auto_save.session!'.
|
||||
|
||||
Should toggle the value and show the new value.
|
||||
"""
|
||||
commands.set(0, 'auto_save.session!', print_=True)
|
||||
msg = message_mock.getmsg(usertypes.MessageLevel.info)
|
||||
assert msg.text == 'auto_save.session = true'
|
||||
|
||||
def test_set_invalid_option(self, commands):
|
||||
"""Run ':set foo bar'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError, match="set: No option 'foo'"):
|
||||
commands.set(0, 'foo', 'bar')
|
||||
|
||||
def test_set_invalid_value(self, commands):
|
||||
"""Run ':set auto_save.session blah'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match="set: Invalid value 'blah' - must be a "
|
||||
"boolean!"):
|
||||
commands.set(0, 'auto_save.session', 'blah')
|
||||
|
||||
def test_set_wrong_backend(self, commands, monkeypatch):
|
||||
monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebEngine)
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match="set: This setting is not available with the "
|
||||
"QtWebEngine backend!"):
|
||||
commands.set(0, 'content.cookies.accept', 'all')
|
||||
|
||||
@pytest.mark.parametrize('option', ['?', '!', 'url.auto_search'])
|
||||
def test_empty(self, commands, option):
|
||||
"""Run ':set ?' / ':set !' / ':set url.auto_search'.
|
||||
|
||||
Should show an error.
|
||||
See https://github.com/qutebrowser/qutebrowser/issues/1109
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match="set: The following arguments are required: "
|
||||
"value"):
|
||||
commands.set(win_id=0, option=option)
|
||||
|
||||
@pytest.mark.parametrize('suffix', '?!')
|
||||
def test_invalid(self, commands, suffix):
|
||||
"""Run ':set foo?' / ':set foo!'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError, match="set: No option 'foo'"):
|
||||
commands.set(win_id=0, option='foo' + suffix)
|
||||
|
||||
@pytest.mark.parametrize('initial, expected', [
|
||||
# Normal cycling
|
||||
('magenta', 'blue'),
|
||||
# Through the end of the list
|
||||
('yellow', 'green'),
|
||||
# Value which is not in the list
|
||||
('red', 'green'),
|
||||
])
|
||||
def test_cycling(self, commands, config_stub, initial, expected):
|
||||
"""Run ':set' with multiple values."""
|
||||
opt = 'colors.statusbar.normal.bg'
|
||||
config_stub.set_obj(opt, initial)
|
||||
commands.set(0, opt, 'green', 'magenta', 'blue', 'yellow')
|
||||
assert config_stub.get(opt) == expected
|
||||
assert config_stub._yaml[opt] == expected
|
||||
|
||||
def test_cycling_different_representation(self, commands, config_stub):
|
||||
"""When using a different representation, cycling should work.
|
||||
|
||||
For example, we use [foo] which is represented as ["foo"].
|
||||
"""
|
||||
opt = 'qt_args'
|
||||
config_stub.set_obj(opt, ['foo'])
|
||||
commands.set(0, opt, '[foo]', '[bar]')
|
||||
assert config_stub.get(opt) == ['bar']
|
||||
commands.set(0, opt, '[foo]', '[bar]')
|
||||
assert config_stub.get(opt) == ['foo']
|
||||
|
||||
|
||||
class TestBindConfigCommand:
|
||||
|
||||
"""Tests for :bind and :unbind."""
|
||||
|
||||
@pytest.fixture
|
||||
def commands(self, config_stub, keyconf):
|
||||
return config.ConfigCommands(config_stub, keyconf)
|
||||
|
||||
@pytest.fixture
|
||||
def no_bindings(self):
|
||||
"""Get a dict with no bindings."""
|
||||
return {'normal': {}}
|
||||
|
||||
@pytest.mark.parametrize('command', ['nop', 'nope'])
|
||||
def test_bind(self, commands, config_stub, no_bindings, keyconf, command):
|
||||
"""Simple :bind test (and aliases)."""
|
||||
config_stub.val.aliases = {'nope': 'nop'}
|
||||
config_stub.val.bindings.default = no_bindings
|
||||
config_stub.val.bindings.commands = no_bindings
|
||||
|
||||
commands.bind('a', command)
|
||||
assert keyconf.get_command('a', 'normal') == command
|
||||
yaml_bindings = config_stub._yaml['bindings.commands']['normal']
|
||||
assert yaml_bindings['a'] == command
|
||||
|
||||
@pytest.mark.parametrize('key, mode, expected', [
|
||||
# Simple
|
||||
('a', 'normal', "a is bound to 'message-info a' in normal mode"),
|
||||
# Alias
|
||||
('b', 'normal', "b is bound to 'mib' in normal mode"),
|
||||
# Custom binding
|
||||
('c', 'normal', "c is bound to 'message-info c' in normal mode"),
|
||||
# Special key
|
||||
('<Ctrl-X>', 'normal',
|
||||
"<ctrl+x> is bound to 'message-info C-x' in normal mode"),
|
||||
# unbound
|
||||
('x', 'normal', "x is unbound in normal mode"),
|
||||
# non-default mode
|
||||
('x', 'caret', "x is bound to 'nop' in caret mode"),
|
||||
])
|
||||
def test_bind_print(self, commands, config_stub, message_mock,
|
||||
key, mode, expected):
|
||||
"""Run ':bind key'.
|
||||
|
||||
Should print the binding.
|
||||
"""
|
||||
config_stub.val.aliases = {'mib': 'message-info b'}
|
||||
config_stub.val.bindings.default = {
|
||||
'normal': {'a': 'message-info a',
|
||||
'b': 'mib',
|
||||
'<Ctrl+x>': 'message-info C-x'},
|
||||
'caret': {'x': 'nop'}
|
||||
}
|
||||
config_stub.val.bindings.commands = {
|
||||
'normal': {'c': 'message-info c'}
|
||||
}
|
||||
|
||||
commands.bind(key, mode=mode)
|
||||
|
||||
msg = message_mock.getmsg(usertypes.MessageLevel.info)
|
||||
assert msg.text == expected
|
||||
|
||||
def test_bind_invalid_mode(self, commands):
|
||||
"""Run ':bind --mode=wrongmode nop'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match='bind: Invalid mode wrongmode!'):
|
||||
commands.bind('a', 'nop', mode='wrongmode')
|
||||
|
||||
@pytest.mark.parametrize('force', [True, False])
|
||||
@pytest.mark.parametrize('key', ['a', 'b', '<Ctrl-X>'])
|
||||
def test_bind_duplicate(self, commands, config_stub, keyconf, force, key):
|
||||
"""Run ':bind' with a key which already has been bound.'.
|
||||
|
||||
Also tests for https://github.com/qutebrowser/qutebrowser/issues/1544
|
||||
"""
|
||||
config_stub.val.bindings.default = {
|
||||
'normal': {'a': 'nop', '<Ctrl+x>': 'nop'}
|
||||
}
|
||||
config_stub.val.bindings.commands = {
|
||||
'normal': {'b': 'nop'},
|
||||
}
|
||||
|
||||
if force:
|
||||
commands.bind(key, 'message-info foo', mode='normal', force=True)
|
||||
assert keyconf.get_command(key, 'normal') == 'message-info foo'
|
||||
else:
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match="bind: Duplicate key .* - use --force to "
|
||||
"override"):
|
||||
commands.bind(key, 'message-info foo', mode='normal')
|
||||
assert keyconf.get_command(key, 'normal') == 'nop'
|
||||
|
||||
def test_bind_none(self, commands, config_stub):
|
||||
config_stub.val.bindings.commands = None
|
||||
commands.bind(',x', 'nop')
|
||||
|
||||
def test_unbind_none(self, commands, config_stub):
|
||||
config_stub.val.bindings.commands = None
|
||||
commands.unbind('H')
|
||||
|
||||
@pytest.mark.parametrize('key, normalized', [
|
||||
('a', 'a'), # default bindings
|
||||
('b', 'b'), # custom bindings
|
||||
('c', 'c'), # :bind then :unbind
|
||||
('<Ctrl-X>', '<ctrl+x>') # normalized special binding
|
||||
])
|
||||
def test_unbind(self, commands, keyconf, config_stub, key, normalized):
|
||||
config_stub.val.bindings.default = {
|
||||
'normal': {'a': 'nop', '<ctrl+x>': 'nop'},
|
||||
'caret': {'a': 'nop', '<ctrl+x>': 'nop'},
|
||||
}
|
||||
config_stub.val.bindings.commands = {
|
||||
'normal': {'b': 'nop'},
|
||||
'caret': {'b': 'nop'},
|
||||
}
|
||||
if key == 'c':
|
||||
# Test :bind and :unbind
|
||||
commands.bind(key, 'nop')
|
||||
|
||||
commands.unbind(key)
|
||||
assert keyconf.get_command(key, 'normal') is None
|
||||
|
||||
yaml_bindings = config_stub._yaml['bindings.commands']['normal']
|
||||
if key in 'bc':
|
||||
# Custom binding
|
||||
assert normalized not in yaml_bindings
|
||||
else:
|
||||
assert yaml_bindings[normalized] is None
|
||||
|
||||
@pytest.mark.parametrize('key, mode, expected', [
|
||||
('foobar', 'normal',
|
||||
"unbind: Can't find binding 'foobar' in normal mode"),
|
||||
('x', 'wrongmode', "unbind: Invalid mode wrongmode!"),
|
||||
])
|
||||
def test_unbind_invalid(self, commands, key, mode, expected):
|
||||
"""Run ':unbind foobar' / ':unbind x wrongmode'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError, match=expected):
|
||||
commands.unbind(key, mode=mode)
|
||||
|
||||
|
||||
class TestConfig:
|
||||
|
||||
@pytest.fixture
|
||||
|
360
tests/unit/config/test_configcommands.py
Normal file
360
tests/unit/config/test_configcommands.py
Normal file
@ -0,0 +1,360 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
|
||||
# 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/>.
|
||||
|
||||
"""Tests for qutebrowser.config.configcommands."""
|
||||
|
||||
import pytest
|
||||
from PyQt5.QtCore import QUrl
|
||||
|
||||
from qutebrowser.config import configcommands
|
||||
from qutebrowser.commands import cmdexc
|
||||
from qutebrowser.utils import objreg, usertypes
|
||||
from qutebrowser.misc import objects
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def commands(config_stub, keyconf):
|
||||
return configcommands.ConfigCommands(config_stub, keyconf)
|
||||
|
||||
|
||||
class TestSetConfigCommand:
|
||||
|
||||
"""Tests for :set."""
|
||||
|
||||
@pytest.fixture
|
||||
def tabbed_browser(self, stubs, win_registry):
|
||||
tb = stubs.TabbedBrowserStub()
|
||||
objreg.register('tabbed-browser', tb, scope='window', window=0)
|
||||
yield tb
|
||||
objreg.delete('tabbed-browser', scope='window', window=0)
|
||||
|
||||
def test_set_no_args(self, commands, tabbed_browser):
|
||||
"""Run ':set'.
|
||||
|
||||
Should open qute://settings."""
|
||||
commands.set(win_id=0)
|
||||
assert tabbed_browser.opened_url == QUrl('qute://settings')
|
||||
|
||||
def test_get(self, config_stub, commands, message_mock):
|
||||
"""Run ':set url.auto_search?'.
|
||||
|
||||
Should show the value.
|
||||
"""
|
||||
config_stub.val.url.auto_search = 'never'
|
||||
commands.set(win_id=0, option='url.auto_search?')
|
||||
msg = message_mock.getmsg(usertypes.MessageLevel.info)
|
||||
assert msg.text == 'url.auto_search = never'
|
||||
|
||||
@pytest.mark.parametrize('temp', [True, False])
|
||||
@pytest.mark.parametrize('option, old_value, inp, new_value', [
|
||||
('url.auto_search', 'naive', 'dns', 'dns'),
|
||||
# https://github.com/qutebrowser/qutebrowser/issues/2962
|
||||
('editor.command', ['gvim', '-f', '{}'], '[emacs, "{}"]',
|
||||
['emacs', '{}']),
|
||||
])
|
||||
def test_set_simple(self, monkeypatch, commands, config_stub,
|
||||
temp, option, old_value, inp, new_value):
|
||||
"""Run ':set [-t] option value'.
|
||||
|
||||
Should set the setting accordingly.
|
||||
"""
|
||||
monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebKit)
|
||||
assert config_stub.get(option) == old_value
|
||||
|
||||
commands.set(0, option, inp, temp=temp)
|
||||
|
||||
assert config_stub.get(option) == new_value
|
||||
|
||||
if temp:
|
||||
assert option not in config_stub._yaml
|
||||
else:
|
||||
assert config_stub._yaml[option] == new_value
|
||||
|
||||
@pytest.mark.parametrize('temp', [True, False])
|
||||
def test_set_temp_override(self, commands, config_stub, temp):
|
||||
"""Invoking :set twice.
|
||||
|
||||
:set url.auto_search dns
|
||||
:set -t url.auto_search never
|
||||
|
||||
Should set the setting accordingly.
|
||||
"""
|
||||
assert config_stub.val.url.auto_search == 'naive'
|
||||
commands.set(0, 'url.auto_search', 'dns')
|
||||
commands.set(0, 'url.auto_search', 'never', temp=True)
|
||||
|
||||
assert config_stub.val.url.auto_search == 'never'
|
||||
assert config_stub._yaml['url.auto_search'] == 'dns'
|
||||
|
||||
def test_set_print(self, config_stub, commands, message_mock):
|
||||
"""Run ':set -p url.auto_search never'.
|
||||
|
||||
Should set show the value.
|
||||
"""
|
||||
assert config_stub.val.url.auto_search == 'naive'
|
||||
commands.set(0, 'url.auto_search', 'dns', print_=True)
|
||||
|
||||
assert config_stub.val.url.auto_search == 'dns'
|
||||
msg = message_mock.getmsg(usertypes.MessageLevel.info)
|
||||
assert msg.text == 'url.auto_search = dns'
|
||||
|
||||
def test_set_toggle(self, commands, config_stub):
|
||||
"""Run ':set auto_save.session!'.
|
||||
|
||||
Should toggle the value.
|
||||
"""
|
||||
assert not config_stub.val.auto_save.session
|
||||
commands.set(0, 'auto_save.session!')
|
||||
assert config_stub.val.auto_save.session
|
||||
assert config_stub._yaml['auto_save.session']
|
||||
|
||||
def test_set_toggle_nonbool(self, commands, config_stub):
|
||||
"""Run ':set url.auto_search!'.
|
||||
|
||||
Should show an error
|
||||
"""
|
||||
assert config_stub.val.url.auto_search == 'naive'
|
||||
with pytest.raises(cmdexc.CommandError, match="set: Can't toggle "
|
||||
"non-bool setting url.auto_search"):
|
||||
commands.set(0, 'url.auto_search!')
|
||||
assert config_stub.val.url.auto_search == 'naive'
|
||||
|
||||
def test_set_toggle_print(self, commands, config_stub, message_mock):
|
||||
"""Run ':set -p auto_save.session!'.
|
||||
|
||||
Should toggle the value and show the new value.
|
||||
"""
|
||||
commands.set(0, 'auto_save.session!', print_=True)
|
||||
msg = message_mock.getmsg(usertypes.MessageLevel.info)
|
||||
assert msg.text == 'auto_save.session = true'
|
||||
|
||||
def test_set_invalid_option(self, commands):
|
||||
"""Run ':set foo bar'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError, match="set: No option 'foo'"):
|
||||
commands.set(0, 'foo', 'bar')
|
||||
|
||||
def test_set_invalid_value(self, commands):
|
||||
"""Run ':set auto_save.session blah'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match="set: Invalid value 'blah' - must be a "
|
||||
"boolean!"):
|
||||
commands.set(0, 'auto_save.session', 'blah')
|
||||
|
||||
def test_set_wrong_backend(self, commands, monkeypatch):
|
||||
monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebEngine)
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match="set: This setting is not available with the "
|
||||
"QtWebEngine backend!"):
|
||||
commands.set(0, 'content.cookies.accept', 'all')
|
||||
|
||||
@pytest.mark.parametrize('option', ['?', '!', 'url.auto_search'])
|
||||
def test_empty(self, commands, option):
|
||||
"""Run ':set ?' / ':set !' / ':set url.auto_search'.
|
||||
|
||||
Should show an error.
|
||||
See https://github.com/qutebrowser/qutebrowser/issues/1109
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match="set: The following arguments are required: "
|
||||
"value"):
|
||||
commands.set(win_id=0, option=option)
|
||||
|
||||
@pytest.mark.parametrize('suffix', '?!')
|
||||
def test_invalid(self, commands, suffix):
|
||||
"""Run ':set foo?' / ':set foo!'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError, match="set: No option 'foo'"):
|
||||
commands.set(win_id=0, option='foo' + suffix)
|
||||
|
||||
@pytest.mark.parametrize('initial, expected', [
|
||||
# Normal cycling
|
||||
('magenta', 'blue'),
|
||||
# Through the end of the list
|
||||
('yellow', 'green'),
|
||||
# Value which is not in the list
|
||||
('red', 'green'),
|
||||
])
|
||||
def test_cycling(self, commands, config_stub, initial, expected):
|
||||
"""Run ':set' with multiple values."""
|
||||
opt = 'colors.statusbar.normal.bg'
|
||||
config_stub.set_obj(opt, initial)
|
||||
commands.set(0, opt, 'green', 'magenta', 'blue', 'yellow')
|
||||
assert config_stub.get(opt) == expected
|
||||
assert config_stub._yaml[opt] == expected
|
||||
|
||||
def test_cycling_different_representation(self, commands, config_stub):
|
||||
"""When using a different representation, cycling should work.
|
||||
|
||||
For example, we use [foo] which is represented as ["foo"].
|
||||
"""
|
||||
opt = 'qt_args'
|
||||
config_stub.set_obj(opt, ['foo'])
|
||||
commands.set(0, opt, '[foo]', '[bar]')
|
||||
assert config_stub.get(opt) == ['bar']
|
||||
commands.set(0, opt, '[foo]', '[bar]')
|
||||
assert config_stub.get(opt) == ['foo']
|
||||
|
||||
|
||||
class TestBindConfigCommand:
|
||||
|
||||
"""Tests for :bind and :unbind."""
|
||||
|
||||
@pytest.fixture
|
||||
def no_bindings(self):
|
||||
"""Get a dict with no bindings."""
|
||||
return {'normal': {}}
|
||||
|
||||
@pytest.mark.parametrize('command', ['nop', 'nope'])
|
||||
def test_bind(self, commands, config_stub, no_bindings, keyconf, command):
|
||||
"""Simple :bind test (and aliases)."""
|
||||
config_stub.val.aliases = {'nope': 'nop'}
|
||||
config_stub.val.bindings.default = no_bindings
|
||||
config_stub.val.bindings.commands = no_bindings
|
||||
|
||||
commands.bind('a', command)
|
||||
assert keyconf.get_command('a', 'normal') == command
|
||||
yaml_bindings = config_stub._yaml['bindings.commands']['normal']
|
||||
assert yaml_bindings['a'] == command
|
||||
|
||||
@pytest.mark.parametrize('key, mode, expected', [
|
||||
# Simple
|
||||
('a', 'normal', "a is bound to 'message-info a' in normal mode"),
|
||||
# Alias
|
||||
('b', 'normal', "b is bound to 'mib' in normal mode"),
|
||||
# Custom binding
|
||||
('c', 'normal', "c is bound to 'message-info c' in normal mode"),
|
||||
# Special key
|
||||
('<Ctrl-X>', 'normal',
|
||||
"<ctrl+x> is bound to 'message-info C-x' in normal mode"),
|
||||
# unbound
|
||||
('x', 'normal', "x is unbound in normal mode"),
|
||||
# non-default mode
|
||||
('x', 'caret', "x is bound to 'nop' in caret mode"),
|
||||
])
|
||||
def test_bind_print(self, commands, config_stub, message_mock,
|
||||
key, mode, expected):
|
||||
"""Run ':bind key'.
|
||||
|
||||
Should print the binding.
|
||||
"""
|
||||
config_stub.val.aliases = {'mib': 'message-info b'}
|
||||
config_stub.val.bindings.default = {
|
||||
'normal': {'a': 'message-info a',
|
||||
'b': 'mib',
|
||||
'<Ctrl+x>': 'message-info C-x'},
|
||||
'caret': {'x': 'nop'}
|
||||
}
|
||||
config_stub.val.bindings.commands = {
|
||||
'normal': {'c': 'message-info c'}
|
||||
}
|
||||
|
||||
commands.bind(key, mode=mode)
|
||||
|
||||
msg = message_mock.getmsg(usertypes.MessageLevel.info)
|
||||
assert msg.text == expected
|
||||
|
||||
def test_bind_invalid_mode(self, commands):
|
||||
"""Run ':bind --mode=wrongmode nop'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match='bind: Invalid mode wrongmode!'):
|
||||
commands.bind('a', 'nop', mode='wrongmode')
|
||||
|
||||
@pytest.mark.parametrize('force', [True, False])
|
||||
@pytest.mark.parametrize('key', ['a', 'b', '<Ctrl-X>'])
|
||||
def test_bind_duplicate(self, commands, config_stub, keyconf, force, key):
|
||||
"""Run ':bind' with a key which already has been bound.'.
|
||||
|
||||
Also tests for https://github.com/qutebrowser/qutebrowser/issues/1544
|
||||
"""
|
||||
config_stub.val.bindings.default = {
|
||||
'normal': {'a': 'nop', '<Ctrl+x>': 'nop'}
|
||||
}
|
||||
config_stub.val.bindings.commands = {
|
||||
'normal': {'b': 'nop'},
|
||||
}
|
||||
|
||||
if force:
|
||||
commands.bind(key, 'message-info foo', mode='normal', force=True)
|
||||
assert keyconf.get_command(key, 'normal') == 'message-info foo'
|
||||
else:
|
||||
with pytest.raises(cmdexc.CommandError,
|
||||
match="bind: Duplicate key .* - use --force to "
|
||||
"override"):
|
||||
commands.bind(key, 'message-info foo', mode='normal')
|
||||
assert keyconf.get_command(key, 'normal') == 'nop'
|
||||
|
||||
def test_bind_none(self, commands, config_stub):
|
||||
config_stub.val.bindings.commands = None
|
||||
commands.bind(',x', 'nop')
|
||||
|
||||
def test_unbind_none(self, commands, config_stub):
|
||||
config_stub.val.bindings.commands = None
|
||||
commands.unbind('H')
|
||||
|
||||
@pytest.mark.parametrize('key, normalized', [
|
||||
('a', 'a'), # default bindings
|
||||
('b', 'b'), # custom bindings
|
||||
('c', 'c'), # :bind then :unbind
|
||||
('<Ctrl-X>', '<ctrl+x>') # normalized special binding
|
||||
])
|
||||
def test_unbind(self, commands, keyconf, config_stub, key, normalized):
|
||||
config_stub.val.bindings.default = {
|
||||
'normal': {'a': 'nop', '<ctrl+x>': 'nop'},
|
||||
'caret': {'a': 'nop', '<ctrl+x>': 'nop'},
|
||||
}
|
||||
config_stub.val.bindings.commands = {
|
||||
'normal': {'b': 'nop'},
|
||||
'caret': {'b': 'nop'},
|
||||
}
|
||||
if key == 'c':
|
||||
# Test :bind and :unbind
|
||||
commands.bind(key, 'nop')
|
||||
|
||||
commands.unbind(key)
|
||||
assert keyconf.get_command(key, 'normal') is None
|
||||
|
||||
yaml_bindings = config_stub._yaml['bindings.commands']['normal']
|
||||
if key in 'bc':
|
||||
# Custom binding
|
||||
assert normalized not in yaml_bindings
|
||||
else:
|
||||
assert yaml_bindings[normalized] is None
|
||||
|
||||
@pytest.mark.parametrize('key, mode, expected', [
|
||||
('foobar', 'normal',
|
||||
"unbind: Can't find binding 'foobar' in normal mode"),
|
||||
('x', 'wrongmode', "unbind: Invalid mode wrongmode!"),
|
||||
])
|
||||
def test_unbind_invalid(self, commands, key, mode, expected):
|
||||
"""Run ':unbind foobar' / ':unbind x wrongmode'.
|
||||
|
||||
Should show an error.
|
||||
"""
|
||||
with pytest.raises(cmdexc.CommandError, match=expected):
|
||||
commands.unbind(key, mode=mode)
|
Loading…
Reference in New Issue
Block a user