Fix completion tests after config merge.

This commit is contained in:
Ryan Roden-Corrent 2017-08-12 15:07:17 -04:00
parent 5ea420b49b
commit 0286e9ddf2
8 changed files with 139 additions and 198 deletions

View File

@ -27,8 +27,9 @@ from qutebrowser.commands import cmdutils
def option():
"""A CompletionModel filled with settings and their descriptions."""
model = completionmodel.CompletionModel(column_widths=(30, 70, 0))
options = [(x.name, x.description) for x in configdata.DATA.values()]
model = completionmodel.CompletionModel(column_widths=(20, 70, 10))
options = ((x.name, x.description, config.instance.get_str(x.name))
for x in configdata.DATA.values())
model.add_category(listcategory.ListCategory("Options", options))
return model
@ -57,23 +58,3 @@ def value(optname, *values):
if vals is not None:
model.add_category(listcategory.ListCategory("Completions", vals))
return model
def bind(key):
"""A CompletionModel filled with all bindable commands and descriptions.
Args:
key: the key being bound.
"""
model = completionmodel.CompletionModel(column_widths=(20, 60, 20))
cmd_text = objreg.get('key-config').get_bindings_for('normal').get(key)
if cmd_text:
cmd_name = cmd_text.split(' ')[0]
cmd = cmdutils.cmd_dict.get(cmd_name)
data = [(cmd_text, cmd.desc, key)]
model.add_category(listcategory.ListCategory("Current", data))
#cmdlist = _get_cmd_completions(include_hidden=True, include_aliases=True)
#model.add_category(listcategory.ListCategory("Commands", cmdlist))
return model

View File

@ -39,22 +39,11 @@ def helptopic():
cmdlist = _get_cmd_completions(include_aliases=False, include_hidden=True,
prefix=':')
settings = []
for sectname, sectdata in configdata.DATA.items():
for optname in sectdata:
try:
desc = sectdata.descriptions[optname]
except (KeyError, AttributeError):
# Some stuff (especially ValueList items) don't have a
# description.
desc = ""
else:
desc = desc.splitlines()[0]
name = '{}->{}'.format(sectname, optname)
settings.append((name, desc))
settings = ((opt.name, opt.description)
for opt in configdata.DATA.values())
model.add_category(listcategory.ListCategory("Commands", cmdlist))
model.add_category(listcategory.ListCategory("Settings", settings))
model.add_category(listcategory.ListCategory("Settings", sorted(settings)))
return model
@ -135,6 +124,26 @@ def buffer():
return model
def bind(key):
"""A CompletionModel filled with all bindable commands and descriptions.
Args:
key: the key being bound.
"""
model = completionmodel.CompletionModel(column_widths=(20, 60, 20))
cmd_text = config.key_instance.get_bindings_for('normal').get(key)
if cmd_text:
cmd_name = cmd_text.split(' ')[0]
cmd = cmdutils.cmd_dict.get(cmd_name)
data = [(cmd_text, cmd.desc, key)]
model.add_category(listcategory.ListCategory("Current", data))
cmdlist = _get_cmd_completions(include_hidden=True, include_aliases=True)
model.add_category(listcategory.ListCategory("Commands", cmdlist))
return model
def _get_cmd_completions(include_hidden, include_aliases, prefix=''):
"""Get a list of completions info for commands, sorted by name.
@ -155,10 +164,9 @@ def _get_cmd_completions(include_hidden, include_aliases, prefix=''):
bindings = ', '.join(cmd_to_keys.get(obj.name, []))
cmdlist.append((prefix + obj.name, obj.desc, bindings))
# FIXME:conf
# if include_aliases:
# for name, cmd in config.section('aliases').items():
# bindings = ', '.join(cmd_to_keys.get(name, []))
# cmdlist.append((name, "Alias for '{}'".format(cmd), bindings))
if include_aliases:
for name, cmd in config.val.aliases.items():
bindings = ', '.join(cmd_to_keys.get(name, []))
cmdlist.append((name, "Alias for '{}'".format(cmd), bindings))
return cmdlist

View File

@ -29,7 +29,7 @@ from qutebrowser.config import configdata, configexc, configtypes, configfiles
from qutebrowser.utils import utils, objreg, message, log, usertypes
from qutebrowser.misc import objects
from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.completion.models import configmodel
from qutebrowser.completion.models import configmodel, miscmodels
# An easy way to access the config from other code via config.val.foo
val = None
@ -311,7 +311,7 @@ class ConfigCommands:
@cmdutils.register(instance='config-commands', maxsplit=1,
no_cmd_split=True, no_replace_variables=True)
@cmdutils.argument('command', completion=configmodel.bind)
@cmdutils.argument('command', completion=miscmodels.bind)
def bind(self, key, command=None, *, mode='normal', force=False):
"""Bind a key to a command.

View File

@ -61,11 +61,11 @@ Feature: Using completion
Then the error "Session hello not found!" should be shown
Scenario: Using option completion
When I run :set-cmd-text -s :set colors
When I run :set-cmd-text -s :set
Then the completion model should be option
Scenario: Using value completion
When I run :set-cmd-text -s :set colors statusbar.bg
When I run :set-cmd-text -s :set aliases
Then the completion model should be value
Scenario: Deleting an open tab via the completion

View File

@ -421,16 +421,6 @@ class FakeYamlConfig:
self.loaded = True
class FakeConfigType:
"""A stub to provide valid_values for typ attribute of a SettingValue."""
def __init__(self, *valid_values):
# normally valid_values would be a ValidValues, but for simplicity of
# testing this can be a simple list: [(val, desc), (val, desc), ...]
self.complete = lambda: [(val, '') for val in valid_values]
class StatusBarCommandStub(QLineEdit):
"""Stub for the statusbar command prompt."""

View File

@ -29,10 +29,6 @@ from qutebrowser.completion import completer
from qutebrowser.commands import command, cmdutils
pytestmark = pytest.mark.skip("FIXME:conf reintroduce after new completion "
"is in")
class FakeCompletionModel(QStandardItemModel):
"""Stub for a completion model."""
@ -67,8 +63,8 @@ def completer_obj(qtbot, status_command_stub, config_stub, monkeypatch, stubs,
completion_widget_stub):
"""Create the completer used for testing."""
monkeypatch.setattr(completer, 'QTimer', stubs.InstaTimer)
config_stub.data = {'completion': {'show': 'auto'}}
return completer.Completer(status_command_stub, 0, completion_widget_stub)
config_stub.val.completion.show = 'auto'
return completer.Completer(status_command_stub, completion_widget_stub)
@pytest.fixture(autouse=True)
@ -246,14 +242,14 @@ def test_on_selection_changed(before, newtxt, after, completer_obj,
"""Test that on_selection_changed modifies the cmd text properly.
The | represents the current cursor position in the cmd prompt.
If quick-complete is True and there is only 1 completion (count == 1),
If quick is True and there is only 1 completion (count == 1),
then we expect a space to be appended after the current word.
"""
model = unittest.mock.Mock()
completion_widget_stub.model.return_value = model
def check(quick_complete, count, expected_txt, expected_pos):
config_stub.data['completion']['quick-complete'] = quick_complete
def check(quick, count, expected_txt, expected_pos):
config_stub.val.completion.quick = quick
model.count = lambda: count
_set_cmd_prompt(status_command_stub, before)
completer_obj.on_selection_changed(newtxt)
@ -288,7 +284,7 @@ def test_quickcomplete_flicker(status_command_stub, completer_obj,
model = unittest.mock.Mock()
model.count = unittest.mock.Mock(return_value=1)
completion_widget_stub.model.return_value = model
config_stub.data['completion']['quick-complete'] = True
config_stub.val.completion.quick = True
_set_cmd_prompt(status_command_stub, ':open |')
completer_obj.on_selection_changed('http://example.com')

View File

@ -29,8 +29,8 @@ from qutebrowser.completion.models import histcategory
@pytest.fixture
def hist(init_sql, config_stub):
config_stub.data['completion'] = {'timestamp-format': '%Y-%m-%d',
'web-history-max-items': -1}
config_stub.val.completion.timestamp_format = '%Y-%m-%d'
config_stub.val.completion.web_history_max_items = -1
return sql.SqlTable('CompletionHistory', ['url', 'title', 'last_atime'])
@ -129,7 +129,7 @@ def test_set_pattern(pattern, before, after, model_validator, hist):
])
def test_sorting(max_items, before, after, model_validator, hist, config_stub):
"""Validate the filtering and sorting results of set_pattern."""
config_stub.data['completion']['web-history-max-items'] = max_items
config_stub.val.completion.web_history_max_items = max_items
for url, title, atime in before:
timestamp = datetime.datetime.strptime(atime, '%Y-%m-%d').timestamp()
hist.insert({'url': url, 'title': title, 'last_atime': timestamp})

View File

@ -29,8 +29,10 @@ import pytest
from PyQt5.QtCore import QUrl
from qutebrowser.completion.models import miscmodels, urlmodel, configmodel
from qutebrowser.config import sections, value, configdata, configtype
from qutebrowser.config import configdata, configtypes
from qutebrowser.utils import objreg
from qutebrowser.browser import history
from qutebrowser.commands import cmdutils
def _check_completions(model, expected):
@ -61,60 +63,69 @@ def _check_completions(model, expected):
assert sum(model.column_widths) == 100
def _patch_cmdutils(monkeypatch, stubs, symbol):
@pytest.fixture()
def cmdutils_stub(monkeypatch, stubs):
"""Patch the cmdutils module to provide fake commands."""
cmd_utils = stubs.FakeCmdUtils({
'stop': stubs.FakeCommand(name='stop', desc='stop qutebrowser'),
'drop': stubs.FakeCommand(name='drop', desc='drop all user data'),
'roll': stubs.FakeCommand(name='roll', desc='never gonna give you up'),
'hide': stubs.FakeCommand(name='hide', hide=True),
'depr': stubs.FakeCommand(name='depr', deprecated=True),
return monkeypatch.setattr(cmdutils, 'cmd_dict', {
'quit': stubs.FakeCommand(name='quit', desc='quit qutebrowser'),
'open': stubs.FakeCommand(name='open', desc='open a url'),
'prompt-yes': stubs.FakeCommand(name='prompt-yes', deprecated=True),
'scroll': stubs.FakeCommand(name='scroll',
desc='Scroll the current tab in the given direction.',
hide=True),
})
monkeypatch.setattr(symbol, cmd_utils)
def _patch_configdata(monkeypatch, stubs, symbol):
@pytest.fixture()
def configdata_stub(monkeypatch, configdata_init):
"""Patch the configdata module to provide fake data."""
data = collections.OrderedDict([
('general.time', configdata.Option(
name='general.time'
('time',
value.SettingValue(stubs.FakeConfigType('fast', 'slow'),
default='slow'),
'Is an illusion.\n\nLunchtime doubly so.'),
('volume',
value.SettingValue(stubs.FakeConfigType('0', '11'),
default='11'),
'Goes to 11'))),
('ui', sections.KeyValue(
('gesture',
value.SettingValue(stubs.FakeConfigType(('on', 'off')),
default='off'),
'Waggle your hands to control qutebrowser'),
('mind',
value.SettingValue(stubs.FakeConfigType(('on', 'off')),
default='off'),
'Enable mind-control ui (experimental)'),
('voice',
value.SettingValue(stubs.FakeConfigType(('on', 'off')),
default='off'),
'Whether to respond to voice commands'))),
('searchengines', sections.ValueList(
stubs.FakeConfigType(), stubs.FakeConfigType(),
('DEFAULT', 'https://duckduckgo.com/?q={}'),
)),
])
monkeypatch.setattr(symbol, data)
def _patch_config_section_desc(monkeypatch, stubs, symbol):
"""Patch the configdata module to provide fake SECTION_DESC."""
section_desc = {
'general': 'General/miscellaneous options.',
'ui': 'General options related to the user interface.',
'searchengines': 'Definitions of search engines ...',
}
monkeypatch.setattr(symbol, section_desc)
return monkeypatch.setattr(configdata, 'DATA', collections.OrderedDict([
('aliases', configdata.Option(
name='aliases',
description='Aliases for commands.',
typ=configtypes.Dict(
keytype=configtypes.String(),
valtype=configtypes.Command(),
),
default={'q': 'quit'},
backends=[],
raw_backends=None)),
('bindings.default', configdata.Option(
name='bindings.default',
description='Default keybindings',
typ=configtypes.Dict(
keytype=configtypes.String(),
valtype=configtypes.Dict(
keytype=configtypes.String(),
valtype=configtypes.Command(),
),
),
default={
'normal': {
'<ctrl+q>': 'quit'
}
},
backends=[],
raw_backends=None)),
('bindings.commands', configdata.Option(
name='bindings.commands',
description='Default keybindings',
typ=configtypes.Dict(
keytype=configtypes.String(),
valtype=configtypes.Dict(
keytype=configtypes.String(),
valtype=configtypes.Command(),
),
),
default={
'normal': {
'<ctrl+q>': 'quit',
'ZQ': 'quit'
}
},
backends=[],
raw_backends=None)),
]))
@pytest.fixture
@ -142,8 +153,8 @@ def bookmarks(bookmark_manager_stub):
@pytest.fixture
def web_history(init_sql, stubs, config_stub):
"""Fixture which provides a web-history object."""
config_stub.completion.timestamp_format = '%Y-%m-%d'
config_stub.completion.web_history_max_items = -1
config_stub.val.completion.timestamp_format = '%Y-%m-%d'
config_stub.val.completion.web_history_max_items = -1
stub = history.WebHistory()
objreg.register('web-history', stub)
yield stub
@ -171,7 +182,7 @@ def web_history_populated(web_history):
return web_history
def test_command_completion(qtmodeltester, monkeypatch, stubs, config_stub,
def test_command_completion(qtmodeltester, cmdutils_stub, configdata_stub,
key_config_stub):
"""Test the results of command completion.
@ -181,12 +192,6 @@ def test_command_completion(qtmodeltester, monkeypatch, stubs, config_stub,
- the binding (if any) is shown in the misc column
- aliases are included
"""
_patch_cmdutils(monkeypatch, stubs,
'qutebrowser.completion.models.miscmodels.cmdutils')
config_stub.aliases = {'rock': 'roll'}
key_config_stub.set_bindings_for('normal', {'s': 'stop',
'rr': 'roll',
'ro': 'rock'})
model = miscmodels.command()
model.set_pattern('')
qtmodeltester.data_display_may_return_none = True
@ -194,28 +199,24 @@ def test_command_completion(qtmodeltester, monkeypatch, stubs, config_stub,
_check_completions(model, {
"Commands": [
('drop', 'drop all user data', ''),
('rock', "Alias for 'roll'", 'ro'),
('roll', 'never gonna give you up', 'rr'),
('stop', 'stop qutebrowser', 's'),
('open', 'open a url', ''),
('q', "Alias for 'quit'", ''),
('quit', 'quit qutebrowser', 'ZQ, <ctrl+q>'),
]
})
def test_help_completion(qtmodeltester, monkeypatch, stubs, key_config_stub):
def test_help_completion(qtmodeltester, cmdutils_stub, key_config_stub,
configdata_stub, config_stub):
"""Test the results of command completion.
Validates that:
- only non-deprecated commands are included
- the command description is shown in the desc column
- the binding (if any) is shown in the misc column
- aliases are included
- aliases are not included
- only the first line of a multiline description is shown
"""
module = 'qutebrowser.completion.models.miscmodels'
key_config_stub.set_bindings_for('normal', {'s': 'stop', 'rr': 'roll'})
_patch_cmdutils(monkeypatch, stubs, module + '.cmdutils')
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
model = miscmodels.helptopic()
model.set_pattern('')
qtmodeltester.data_display_may_return_none = True
@ -223,18 +224,14 @@ def test_help_completion(qtmodeltester, monkeypatch, stubs, key_config_stub):
_check_completions(model, {
"Commands": [
(':drop', 'drop all user data', ''),
(':hide', '', ''),
(':roll', 'never gonna give you up', 'rr'),
(':stop', 'stop qutebrowser', 's'),
(':open', 'open a url', ''),
(':quit', 'quit qutebrowser', 'ZQ, <ctrl+q>'),
(':scroll', 'Scroll the current tab in the given direction.', '')
],
"Settings": [
('general->time', 'Is an illusion.', None),
('general->volume', 'Goes to 11', None),
('searchengines->DEFAULT', '', None),
('ui->gesture', 'Waggle your hands to control qutebrowser', None),
('ui->mind', 'Enable mind-control ui (experimental)', None),
('ui->voice', 'Whether to respond to voice commands', None),
('aliases', 'Aliases for commands.', None),
('bindings.commands', 'Default keybindings', None),
('bindings.default', 'Default keybindings', None),
]
})
@ -444,7 +441,7 @@ def test_url_completion_delete_history(qtmodeltester,
def test_url_completion_zero_limit(config_stub, web_history, quickmarks,
bookmarks):
"""Make sure there's no history if the limit was set to zero."""
config_stub.completion.web_history_max_items = 0
config_stub.val.completion.web_history_max_items = 0
model = urlmodel.url()
model.set_pattern('')
category = model.index(2, 0) # "History" normally
@ -521,80 +518,49 @@ def test_tab_completion_delete(qtmodeltester, fake_web_tab, app_stub,
QUrl('https://duckduckgo.com')]
def test_setting_option_completion(qtmodeltester, monkeypatch, stubs):
module = 'qutebrowser.completion.models.configmodel'
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
model = configmodel.option('ui')
def test_setting_option_completion(qtmodeltester, config_stub,
configdata_stub):
model = configmodel.option()
model.set_pattern('')
qtmodeltester.data_display_may_return_none = True
qtmodeltester.check(model)
_check_completions(model, {
"ui": [
('gesture', 'Waggle your hands to control qutebrowser', 'off'),
('mind', 'Enable mind-control ui (experimental)', 'on'),
('voice', 'Whether to respond to voice commands', 'sometimes'),
"Options": [
('aliases', 'Aliases for commands.', '{"q": "quit"}'),
('bindings.commands', 'Default keybindings',
'{"normal": {"<ctrl+q>": "quit", "ZQ": "quit"}}'),
('bindings.default', 'Default keybindings',
'{"normal": {"<ctrl+q>": "quit"}}'),
]
})
def test_setting_option_completion_empty(monkeypatch, stubs, config_stub):
module = 'qutebrowser.completion.models.configmodel'
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
assert configmodel.option('typo') is None
def test_setting_option_completion_valuelist(qtmodeltester, monkeypatch, stubs,
config_stub):
module = 'qutebrowser.completion.models.configmodel'
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
config_stub.data = {
'searchengines': {
'DEFAULT': 'https://duckduckgo.com/?q={}'
}
}
model = configmodel.option('searchengines')
model.set_pattern('')
qtmodeltester.data_display_may_return_none = True
qtmodeltester.check(model)
_check_completions(model, {
'searchengines': [('DEFAULT', '', 'https://duckduckgo.com/?q={}')]
})
def test_bind_completion(qtmodeltester, monkeypatch, stubs, config_stub,
key_config_stub):
def test_bind_completion(qtmodeltester, cmdutils_stub, config_stub,
key_config_stub, configdata_stub):
"""Test the results of keybinding command completion.
Validates that:
- only non-hidden and non-deprecated commands are included
- only non-deprecated commands are included
- the command description is shown in the desc column
- the binding (if any) is shown in the misc column
- aliases are included
"""
_patch_cmdutils(monkeypatch, stubs,
'qutebrowser.completion.models.miscmodels.cmdutils')
config_stub.data['aliases'] = {'rock': 'roll'}
key_config_stub.set_bindings_for('normal', {'s': 'stop now',
'rr': 'roll',
'ro': 'rock'})
model = miscmodels.bind('s')
model = miscmodels.bind('ZQ')
model.set_pattern('')
qtmodeltester.data_display_may_return_none = True
qtmodeltester.check(model)
_check_completions(model, {
"Current": [
('stop now', 'stop qutebrowser', 's'),
('quit', 'quit qutebrowser', 'ZQ'),
],
"Commands": [
('drop', 'drop all user data', ''),
('hide', '', ''),
('rock', "Alias for 'roll'", 'ro'),
('roll', 'never gonna give you up', 'rr'),
('stop', 'stop qutebrowser', ''),
]
('open', 'open a url', ''),
('q', "Alias for 'quit'", ''),
('quit', 'quit qutebrowser', 'ZQ, <ctrl+q>'),
('scroll', 'Scroll the current tab in the given direction.', '')
],
})