5b22209eef
See #2777
309 lines
10 KiB
Python
309 lines
10 KiB
Python
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
|
# Copyright 2015-2018 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.configdata."""
|
|
|
|
import textwrap
|
|
|
|
import yaml
|
|
import pytest
|
|
|
|
# To run cmdutils.register decorators
|
|
from qutebrowser import app # pylint: disable=unused-import
|
|
from qutebrowser.config import configdata, configtypes
|
|
from qutebrowser.utils import usertypes
|
|
|
|
|
|
def test_init(config_stub):
|
|
"""Test reading the default yaml file."""
|
|
# configdata.init() is called by config_stub
|
|
config_stub.val.aliases = {}
|
|
assert isinstance(configdata.DATA, dict)
|
|
assert 'search.ignore_case' in configdata.DATA
|
|
|
|
|
|
def test_data(config_stub):
|
|
"""Test various properties of the default values."""
|
|
for option in configdata.DATA.values():
|
|
# Make sure to_py and to_str work
|
|
option.typ.to_py(option.default)
|
|
option.typ.to_str(option.default)
|
|
|
|
# https://github.com/qutebrowser/qutebrowser/issues/3104
|
|
# For lists/dicts, don't use None as default
|
|
if isinstance(option.typ, (configtypes.Dict, configtypes.List)):
|
|
assert option.default is not None
|
|
# For ListOrValue, use a list as default
|
|
if isinstance(option.typ, configtypes.ListOrValue):
|
|
assert isinstance(option.default, list)
|
|
|
|
|
|
def test_init_benchmark(benchmark):
|
|
benchmark(configdata.init)
|
|
|
|
|
|
def test_is_valid_prefix(monkeypatch):
|
|
monkeypatch.setattr(configdata, 'DATA', ['foo.bar'])
|
|
assert configdata.is_valid_prefix('foo')
|
|
assert not configdata.is_valid_prefix('foo.bar')
|
|
assert not configdata.is_valid_prefix('foa')
|
|
|
|
|
|
class TestReadYaml:
|
|
|
|
def test_valid(self):
|
|
yaml_data = textwrap.dedent("""
|
|
test1:
|
|
type: Bool
|
|
default: true
|
|
desc: Hello World
|
|
|
|
test2:
|
|
type: String
|
|
default: foo
|
|
backend: QtWebKit
|
|
desc: Hello World 2
|
|
""")
|
|
data, _migrations = configdata._read_yaml(yaml_data)
|
|
assert data.keys() == {'test1', 'test2'}
|
|
assert data['test1'].description == "Hello World"
|
|
assert data['test2'].default == "foo"
|
|
assert data['test2'].backends == [usertypes.Backend.QtWebKit]
|
|
assert isinstance(data['test1'].typ, configtypes.Bool)
|
|
|
|
def test_invalid_keys(self):
|
|
"""Test reading with unknown keys."""
|
|
data = textwrap.dedent("""
|
|
test:
|
|
type: Bool
|
|
default: true
|
|
desc: Hello World
|
|
hello: world
|
|
""",)
|
|
with pytest.raises(ValueError, match='Invalid keys'):
|
|
configdata._read_yaml(data)
|
|
|
|
@pytest.mark.parametrize('first, second, shadowing', [
|
|
('foo', 'foo.bar', True),
|
|
('foo.bar', 'foo', True),
|
|
('foo.bar', 'foo.bar.baz', True),
|
|
('foo.bar', 'foo.baz', False),
|
|
])
|
|
def test_shadowing(self, first, second, shadowing):
|
|
"""Make sure a setting can't shadow another."""
|
|
data = textwrap.dedent("""
|
|
{first}:
|
|
type: Bool
|
|
default: true
|
|
desc: Hello World
|
|
|
|
{second}:
|
|
type: Bool
|
|
default: true
|
|
desc: Hello World
|
|
""".format(first=first, second=second))
|
|
if shadowing:
|
|
with pytest.raises(ValueError, match='Shadowing keys'):
|
|
configdata._read_yaml(data)
|
|
else:
|
|
configdata._read_yaml(data)
|
|
|
|
def test_rename(self):
|
|
yaml_data = textwrap.dedent("""
|
|
test:
|
|
renamed: test_new
|
|
|
|
test_new:
|
|
type: Bool
|
|
default: true
|
|
desc: Hello World
|
|
""")
|
|
data, migrations = configdata._read_yaml(yaml_data)
|
|
assert data.keys() == {'test_new'}
|
|
assert migrations.renamed == {'test': 'test_new'}
|
|
|
|
def test_rename_unknown_target(self):
|
|
yaml_data = textwrap.dedent("""
|
|
test:
|
|
renamed: test2
|
|
""")
|
|
with pytest.raises(ValueError, match='Renaming test to unknown test2'):
|
|
configdata._read_yaml(yaml_data)
|
|
|
|
def test_delete(self):
|
|
yaml_data = textwrap.dedent("""
|
|
test:
|
|
deleted: true
|
|
""")
|
|
data, migrations = configdata._read_yaml(yaml_data)
|
|
assert not data.keys()
|
|
assert migrations.deleted == ['test']
|
|
|
|
def test_delete_invalid_value(self):
|
|
yaml_data = textwrap.dedent("""
|
|
test:
|
|
deleted: false
|
|
""")
|
|
with pytest.raises(ValueError, match='Invalid deleted value: False'):
|
|
configdata._read_yaml(yaml_data)
|
|
|
|
|
|
class TestParseYamlType:
|
|
|
|
def _yaml(self, s):
|
|
"""Get the type from parsed YAML data."""
|
|
return yaml.load(textwrap.dedent(s))['type']
|
|
|
|
def test_simple(self):
|
|
"""Test type which is only a name."""
|
|
data = self._yaml("type: Bool")
|
|
typ = configdata._parse_yaml_type('test', data)
|
|
assert isinstance(typ, configtypes.Bool)
|
|
assert not typ.none_ok
|
|
|
|
def test_complex(self):
|
|
"""Test type parsing with arguments."""
|
|
data = self._yaml("""
|
|
type:
|
|
name: String
|
|
minlen: 2
|
|
""")
|
|
typ = configdata._parse_yaml_type('test', data)
|
|
assert isinstance(typ, configtypes.String)
|
|
assert not typ.none_ok
|
|
assert typ.minlen == 2
|
|
|
|
def test_list(self):
|
|
"""Test type parsing with a list and subtypes."""
|
|
data = self._yaml("""
|
|
type:
|
|
name: List
|
|
valtype: String
|
|
""")
|
|
typ = configdata._parse_yaml_type('test', data)
|
|
assert isinstance(typ, configtypes.List)
|
|
assert isinstance(typ.valtype, configtypes.String)
|
|
assert not typ.none_ok
|
|
assert not typ.valtype.none_ok
|
|
|
|
def test_dict(self):
|
|
"""Test type parsing with a dict and subtypes."""
|
|
data = self._yaml("""
|
|
type:
|
|
name: Dict
|
|
keytype: String
|
|
valtype:
|
|
name: Int
|
|
minval: 10
|
|
""")
|
|
typ = configdata._parse_yaml_type('test', data)
|
|
assert isinstance(typ, configtypes.Dict)
|
|
assert isinstance(typ.keytype, configtypes.String)
|
|
assert isinstance(typ.valtype, configtypes.Int)
|
|
assert not typ.none_ok
|
|
assert typ.valtype.minval == 10
|
|
|
|
def test_invalid_node(self):
|
|
"""Test type parsing with invalid node type."""
|
|
data = self._yaml("type: 42")
|
|
with pytest.raises(ValueError, match="Invalid node for test while "
|
|
"reading type: 42"):
|
|
configdata._parse_yaml_type('test', data)
|
|
|
|
def test_unknown_type(self):
|
|
"""Test type parsing with type which doesn't exist."""
|
|
data = self._yaml("type: Foobar")
|
|
with pytest.raises(AttributeError,
|
|
match="Did not find type Foobar for test"):
|
|
configdata._parse_yaml_type('test', data)
|
|
|
|
def test_unknown_dict(self):
|
|
"""Test type parsing with a dict without keytype."""
|
|
data = self._yaml("type: Dict")
|
|
with pytest.raises(ValueError, match="Invalid node for test while "
|
|
"reading 'keytype': 'Dict'"):
|
|
configdata._parse_yaml_type('test', data)
|
|
|
|
def test_unknown_args(self):
|
|
"""Test type parsing with unknown type arguments."""
|
|
data = self._yaml("""
|
|
type:
|
|
name: Int
|
|
answer: 42
|
|
""")
|
|
with pytest.raises(TypeError, match="Error while creating Int"):
|
|
configdata._parse_yaml_type('test', data)
|
|
|
|
|
|
class TestParseYamlBackend:
|
|
|
|
def _yaml(self, s):
|
|
"""Get the type from parsed YAML data."""
|
|
return yaml.load(textwrap.dedent(s))['backend']
|
|
|
|
@pytest.mark.parametrize('backend, expected', [
|
|
('QtWebKit', [usertypes.Backend.QtWebKit]),
|
|
('QtWebEngine', [usertypes.Backend.QtWebEngine]),
|
|
# This is also what _parse_yaml_backends gets when backend: is not
|
|
# given at all
|
|
('null', [usertypes.Backend.QtWebKit, usertypes.Backend.QtWebEngine]),
|
|
])
|
|
def test_simple(self, backend, expected):
|
|
"""Check a simple "backend: QtWebKit"."""
|
|
data = self._yaml("backend: {}".format(backend))
|
|
backends = configdata._parse_yaml_backends('test', data)
|
|
assert backends == expected
|
|
|
|
@pytest.mark.parametrize('webkit, has_new_version, expected', [
|
|
(True, True, [usertypes.Backend.QtWebEngine,
|
|
usertypes.Backend.QtWebKit]),
|
|
(False, True, [usertypes.Backend.QtWebEngine]),
|
|
(True, False, [usertypes.Backend.QtWebKit]),
|
|
])
|
|
def test_dict(self, monkeypatch, webkit, has_new_version, expected):
|
|
data = self._yaml("""
|
|
backend:
|
|
QtWebKit: {}
|
|
QtWebEngine: Qt 5.8
|
|
""".format('true' if webkit else 'false'))
|
|
monkeypatch.setattr(configdata.qtutils, 'version_check',
|
|
lambda v: has_new_version)
|
|
backends = configdata._parse_yaml_backends('test', data)
|
|
assert backends == expected
|
|
|
|
@pytest.mark.parametrize('yaml_data', [
|
|
# Wrong type
|
|
"backend: 42",
|
|
# Unknown key
|
|
"""
|
|
backend:
|
|
QtWebKit: true
|
|
QtWebEngine: true
|
|
foo: bar
|
|
""",
|
|
# Missing key
|
|
"""
|
|
backend:
|
|
QtWebKit: true
|
|
""",
|
|
])
|
|
def test_invalid_backend(self, yaml_data):
|
|
with pytest.raises(ValueError, match="Invalid node for test while "
|
|
"reading backends:"):
|
|
configdata._parse_yaml_backends('test', self._yaml(yaml_data))
|