From a8c7e8ba05b6a845d755e35f3bfe870790991a8b Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sun, 2 Jul 2017 17:12:31 +0200 Subject: [PATCH] Add first config tests --- qutebrowser/config/config.py | 6 +- tests/unit/config/test_config.py | 123 +++++++++++++++++++++++++++++-- 2 files changed, 119 insertions(+), 10 deletions(-) diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index ff57e0e06..8d7ed821c 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -137,7 +137,7 @@ class KeyConfig: bindings = dict(val.bindings.default[mode]) for key, binding in val.bindings.commands[mode].items(): if binding is None: - del bindings[key] + bindings.pop(key, None) else: bindings[key] = binding return bindings @@ -146,9 +146,7 @@ class KeyConfig: """Get a dict of commands to a list of bindings for the mode.""" cmd_to_keys = {} bindings = self.get_bindings_for(mode) - if bindings is None: - return cmd_to_keys - for key, full_cmd in bindings.items(): + for key, full_cmd in sorted(bindings.items()): for cmd in full_cmd.split(';;'): cmd = cmd.strip() cmd_to_keys.setdefault(cmd, []) diff --git a/tests/unit/config/test_config.py b/tests/unit/config/test_config.py index 0d993a63d..ebb579e00 100644 --- a/tests/unit/config/test_config.py +++ b/tests/unit/config/test_config.py @@ -18,13 +18,124 @@ """Tests for qutebrowser.config.config.""" +import copy + import pytest from PyQt5.QtCore import QObject -from qutebrowser.config import config +from qutebrowser.config import config, configdata, configexc -class Obj(QObject): +@pytest.fixture(autouse=True) +def configdata_init(): + """Initialize configdata if needed.""" + if configdata.DATA is None: + configdata.init() + + +class TestChangeFilter: + + @pytest.mark.parametrize('option', ['foobar', 'tab', 'tabss', 'tabs.']) + def test_unknown_option(self, option): + cf = config.change_filter(option) + with pytest.raises(configexc.NoOptionError): + cf.validate() + + @pytest.mark.parametrize('option', ['confirm_quit', 'tabs', 'tabs.show']) + def test_validate(self, option): + cf = config.change_filter(option) + cf.validate() + assert cf in config._change_filters + + @pytest.mark.parametrize('method', [True, False]) + @pytest.mark.parametrize('option, changed, matches', [ + ('confirm_quit', 'confirm_quit', True), + ('tabs', 'tabs.show', True), + ('tabs.show', 'tabs.show', True), + ('tabs', None, True), + ('tabs', 'colors.tabs.bar.bg', False), + ]) + def test_call(self, method, option, changed, matches): + was_called = False + if method: + + class Foo: + + @config.change_filter(option) + def meth(self): + nonlocal was_called + was_called = True + + foo = Foo() + foo.meth(changed) + + else: + + @config.change_filter(option, function=True) + def func(): + nonlocal was_called + was_called = True + + func(changed) + + assert was_called == matches + + +class TestKeyConfig: + + @pytest.fixture + def keyconf(self, config_stub): + return config.KeyConfig(config_stub) + + @pytest.mark.parametrize('commands, expected', [ + # Unbinding default key + ({'a': None}, {'b': 'bar'}), + # Additional binding + ({'c': 'baz'}, {'a': 'foo', 'b': 'bar', 'c': 'baz'}), + # Unbinding unknown key + ({'x': None}, {'a': 'foo', 'b': 'bar'}), + ]) + def test_get_bindings_for(self, keyconf, config_stub, commands, expected): + orig_default_bindings = {'normal': {'a': 'foo', 'b': 'bar'}} + config_stub.val.bindings.default = copy.deepcopy(orig_default_bindings) + config_stub.val.bindings.commands = {'normal': commands} + bindings = keyconf.get_bindings_for('normal') + + # Make sure the code creates a copy and doesn't modify the setting + assert config_stub.val.bindings.default == orig_default_bindings + assert bindings == expected + + @pytest.mark.parametrize('bindings, expected', [ + # Simple + ({'a': 'foo', 'b': 'bar'}, {'foo': ['a'], 'bar': ['b']}), + # Multiple bindings + ({'a': 'foo', 'b': 'foo'}, {'foo': ['b', 'a']}), + # With special keys (should be listed last) + ({'a': 'foo', '': 'foo'}, {'foo': ['a', '']}), + # Chained command + ({'a': 'foo ;; bar'}, {'foo': ['a'], 'bar': ['a']}), + ]) + def test_get_reverse_bindings_for(self, keyconf, config_stub, bindings, + expected): + config_stub.val.bindings.default = {'normal': {}} + config_stub.val.bindings.commands = {'normal': bindings} + assert keyconf.get_reverse_bindings_for('normal') == expected + + @pytest.mark.parametrize('key, expected', [ + ('A', 'A'), + ('', ''), + ]) + def test_prepare_valid(self, keyconf, key, expected): + """Make sure prepare normalizes the key.""" + assert keyconf._prepare(key, 'normal') == expected + + def test_prepare_invalid(self, keyconf): + """Make sure prepare checks the mode.""" + with pytest.raises(configexc.KeybindingError): + assert keyconf._prepare('x', 'abnormal') + + +class StyleObj(QObject): def __init__(self, stylesheet=None, parent=None): super().__init__(parent) @@ -39,7 +150,7 @@ class Obj(QObject): def test_get_stylesheet(config_stub): config_stub.val.colors.completion.bg = 'magenta' observer = config.StyleSheetObserver( - Obj(), stylesheet="{{ conf.colors.completion.bg }}") + StyleObj(), stylesheet="{{ conf.colors.completion.bg }}") assert observer._get_stylesheet() == 'magenta' @@ -53,15 +164,15 @@ def test_set_register_stylesheet(delete, stylesheet_param, update, qtbot, with caplog.at_level(9): # VDEBUG if stylesheet_param: - obj = Obj() + obj = StyleObj() config.set_register_stylesheet(obj, stylesheet=stylesheet, update=update) else: - obj = Obj(stylesheet) + obj = StyleObj(stylesheet) config.set_register_stylesheet(obj, update=update) assert len(caplog.records) == 1 - assert caplog.records[0].message == 'stylesheet for Obj: magenta' + assert caplog.records[0].message == 'stylesheet for StyleObj: magenta' assert obj.rendered_stylesheet == 'magenta'