diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py index 056633ca7..aab210bf1 100644 --- a/qutebrowser/config/configfiles.py +++ b/qutebrowser/config/configfiles.py @@ -257,7 +257,7 @@ class ConfigPyWriter: def write(self, filename): """Write the config to the given file.""" with open(filename, 'w', encoding='utf-8') as f: - f.write('\n'.join(self._gen_text())) + f.write('\n'.join(self._gen_lines())) def _line(self, line): """Get an (optionally commented) line.""" @@ -269,7 +269,7 @@ class ConfigPyWriter: else: return line - def _gen_text(self): + def _gen_lines(self): """Generate a config.py with the given settings/bindings. Yields individual lines. @@ -279,11 +279,12 @@ class ConfigPyWriter: yield from self._gen_bindings() def _gen_header(self): - """Generate the intiial header of the config.""" + """Generate the initial header of the config.""" yield self._line("# Autogenerated config.py") yield self._line("# Documentation:") yield self._line("# qute://help/configuring.html") - yield self._line("# qute://help/settings.html\n") + yield self._line("# qute://help/settings.html") + yield '' if self._commented: # When generated from an autoconfig.yml with commented=False, # we don't want to load that autoconfig.yml anymore. @@ -291,11 +292,13 @@ class ConfigPyWriter: "still loaded.") yield self._line("# Remove it to not load settings done via the " "GUI.") - yield self._line("config.load_autoconfig()\n") + yield self._line("config.load_autoconfig()") + yield '' else: yield self._line("# Uncomment this to still load settings " "configured via autoconfig.yml") - yield self._line("# config.load_autoconfig()\n") + yield self._line("# config.load_autoconfig()") + yield '' def _gen_options(self): """Generate the options part of the config.""" @@ -318,7 +321,8 @@ class ConfigPyWriter: except KeyError: yield self._line("# - {}".format(val)) - yield self._line('c.{} = {!r}\n'.format(opt.name, value)) + yield self._line('c.{} = {!r}'.format(opt.name, value)) + yield '' def _gen_bindings(self): """Generate the bindings part of the config.""" diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py index 6233369f7..cef035a1f 100644 --- a/tests/unit/config/test_configfiles.py +++ b/tests/unit/config/test_configfiles.py @@ -21,11 +21,13 @@ import os import sys import unittest.mock +import textwrap import pytest -from qutebrowser.config import config, configfiles, configexc, configdata -from qutebrowser.utils import utils +from qutebrowser.config import (config, configfiles, configexc, configdata, + configtypes) +from qutebrowser.utils import utils, usertypes from PyQt5.QtCore import QSettings @@ -527,6 +529,138 @@ class TestConfigPy: assert error.traceback is not None +class TestConfigPyWriter: + + def test_output(self): + desc = ("This is an option description.\n\n" + "Nullam eu ante vel est convallis dignissim. Fusce suscipit, " + "wisi nec facilisis facilisis, est dui fermentum leo, quis " + "tempor ligula erat quis odio.") + opt = configdata.Option( + name='opt', typ=configtypes.Int(), default='def', + backends=[usertypes.Backend.QtWebEngine], raw_backends=None, + description=desc) + options = [(opt, 'val')] + bindings = {'normal': {',x': 'message-info normal'}, + 'caret': {',y': 'message-info caret'}} + + writer = configfiles.ConfigPyWriter(options, bindings, commented=False) + text = '\n'.join(writer._gen_lines()) + + assert text == textwrap.dedent(""" + # Autogenerated config.py + # Documentation: + # qute://help/configuring.html + # qute://help/settings.html + + # Uncomment this to still load settings configured via autoconfig.yml + # config.load_autoconfig() + + # This is an option description. Nullam eu ante vel est convallis + # dignissim. Fusce suscipit, wisi nec facilisis facilisis, est dui + # fermentum leo, quis tempor ligula erat quis odio. + # Type: Int + c.opt = 'val' + + # Bindings for normal mode + config.bind(',x', 'message-info normal') + + # Bindings for caret mode + config.bind(',y', 'message-info caret', mode='caret') + """).strip() + + def test_binding_options_hidden(self): + opt1 = configdata.DATA['bindings.default'] + opt2 = configdata.DATA['bindings.commands'] + options = [(opt1, {'normal': {'x': 'message-info x'}}), + (opt2, {})] + writer = configfiles.ConfigPyWriter(options, bindings={}, + commented=False) + text = '\n'.join(writer._gen_lines()) + assert 'bindings.default' not in text + assert 'bindings.commands' not in text + + def test_commented(self): + opt = configdata.Option( + name='opt', typ=configtypes.Int(), default='def', + backends=[usertypes.Backend.QtWebEngine], raw_backends=None, + description='Hello World') + options = [(opt, 'val')] + bindings = {'normal': {',x': 'message-info normal'}, + 'caret': {',y': 'message-info caret'}} + + writer = configfiles.ConfigPyWriter(options, bindings, commented=True) + lines = list(writer._gen_lines()) + + assert "## Autogenerated config.py" in lines + assert "# config.load_autoconfig()" in lines + assert "# c.opt = 'val'" in lines + assert "## Bindings for normal mode" in lines + assert "# config.bind(',x', 'message-info normal')" in lines + caret_bind = ("# config.bind(',y', 'message-info caret', " + "mode='caret')") + assert caret_bind in lines + + def test_valid_values(self): + opt1 = configdata.Option( + name='opt1', typ=configtypes.BoolAsk(), default='ask', + backends=[usertypes.Backend.QtWebEngine], raw_backends=None, + description='Hello World') + opt2 = configdata.Option( + name='opt2', typ=configtypes.ColorSystem(), default='rgb', + backends=[usertypes.Backend.QtWebEngine], raw_backends=None, + description='All colors are beautiful!') + + options = [(opt1, 'ask'), (opt2, 'rgb')] + + writer = configfiles.ConfigPyWriter(options, bindings={}, + commented=False) + text = '\n'.join(writer._gen_lines()) + + expected = textwrap.dedent(""" + # Hello World + # Type: BoolAsk + # Valid values: + # - true + # - false + # - ask + c.opt1 = 'ask' + + # All colors are beautiful! + # Type: ColorSystem + # Valid values: + # - rgb: Interpolate in the RGB color system. + # - hsv: Interpolate in the HSV color system. + # - hsl: Interpolate in the HSL color system. + # - none: Don't show a gradient. + c.opt2 = 'rgb' + """) + assert expected in text + + def test_empty(self): + writer = configfiles.ConfigPyWriter(options=[], bindings={}, + commented=False) + text = '\n'.join(writer._gen_lines()) + expected = textwrap.dedent(""" + # Autogenerated config.py + # Documentation: + # qute://help/configuring.html + # qute://help/settings.html + + # Uncomment this to still load settings configured via autoconfig.yml + # config.load_autoconfig() + """).lstrip() + assert text == expected + + def test_write(self, tmpdir): + pyfile = tmpdir / 'config.py' + writer = configfiles.ConfigPyWriter(options=[], bindings={}, + commented=False) + writer.write(str(pyfile)) + lines = pyfile.read_text('utf-8').splitlines() + assert '# Autogenerated config.py' in lines + + @pytest.fixture def init_patch(qapp, fake_save_manager, config_tmpdir, data_tmpdir, config_stub, monkeypatch):