qutebrowser/tests/unit/config/test_configdata.py
Florian Bruhin d69c6d0c66 Reorganize how configtypes store their data
Now the "object" kind of value (like in YAML) is stored internally, and that's
the canonical value. The methods changed their meaning slightly, see the
docstring in configtypes.py for details.
2017-07-04 15:08:02 +02:00

253 lines
8.4 KiB
Python

# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-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.configdata."""
import textwrap
import yaml
import pytest
from qutebrowser.config import configdata, configtypes
from qutebrowser.utils import usertypes
def test_init():
"""Test reading the default yaml file and validating the values."""
configdata.init()
assert isinstance(configdata.DATA, dict)
assert 'ignore_case' in configdata.DATA
for option in configdata.DATA.values():
option.typ.to_py(option.default)
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):
data = textwrap.dedent("""
test1:
type: Bool
default: true
desc: Hello World
test2:
type: String
default: foo
backend: QtWebKit
desc: Hello World 2
""")
data = configdata._read_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)
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.QtWebKit,
usertypes.Backend.QtWebEngine]),
(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))