Reject hints -> chars containing duplicate chars

Fixes #1286.
This commit is contained in:
Florian Bruhin 2016-02-03 21:05:35 +01:00
parent 0b491f6caf
commit e5e1a0d95c
4 changed files with 32 additions and 11 deletions

View File

@ -48,6 +48,7 @@ Fixed
- Fixed crash when downloading a file without any path information (e.g a - Fixed crash when downloading a file without any path information (e.g a
magnet link). magnet link).
- Fixed crashes when opening an empty URL (e.g. via pasting). - Fixed crashes when opening an empty URL (e.g. via pasting).
- Fixed validation of duplicate values in `hints -> chars`.
v0.5.1 v0.5.1
------ ------

View File

@ -870,7 +870,7 @@ def data(readonly=False):
"Mode to use for hints."), "Mode to use for hints."),
('chars', ('chars',
SettingValue(typ.String(minlen=2, completions=[ SettingValue(typ.UniqueCharString(minlen=2, completions=[
('asdfghjkl', "Home row"), ('asdfghjkl', "Home row"),
('dhtnaoeu', "Home row (Dvorak)"), ('dhtnaoeu', "Home row (Dvorak)"),
('abcdefghijklmnopqrstuvwxyz', "All letters"), ('abcdefghijklmnopqrstuvwxyz', "All letters"),

View File

@ -283,6 +283,21 @@ class String(BaseType):
return super().complete() return super().complete()
class UniqueCharString(String):
"""A string which may not contain duplicate chars."""
def validate(self, value):
super().validate(value)
if not value:
return
# Check for duplicate values
if len(set(value)) != len(value):
raise configexc.ValidationError(
value, "String contains duplicate values!")
class List(BaseType): class List(BaseType):
"""Base class for a (string-)list setting.""" """Base class for a (string-)list setting."""

View File

@ -278,9 +278,9 @@ class TestString:
"""Test String.""" """Test String."""
@pytest.fixture @pytest.fixture(params=[configtypes.String, configtypes.UniqueCharString])
def klass(self): def klass(self, request):
return configtypes.String return request.param
@pytest.mark.parametrize('minlen, maxlen', [(1, None), (None, 1)]) @pytest.mark.parametrize('minlen, maxlen', [(1, None), (None, 1)])
def test_lengths_valid(self, klass, minlen, maxlen): def test_lengths_valid(self, klass, minlen, maxlen):
@ -297,16 +297,16 @@ class TestString:
@pytest.mark.parametrize('kwargs, val', [ @pytest.mark.parametrize('kwargs, val', [
({'none_ok': True}, ''), # Empty with none_ok ({'none_ok': True}, ''), # Empty with none_ok
({}, "Hello World! :-)"), ({}, "Test! :-)"),
# Forbidden chars # Forbidden chars
({'forbidden': 'xyz'}, 'foobar'), ({'forbidden': 'xyz'}, 'fobar'),
({'forbidden': 'xyz'}, 'foXbar'), ({'forbidden': 'xyz'}, 'foXbar'),
# Lengths # Lengths
({'minlen': 2}, 'fo'), ({'minlen': 2}, 'fo'),
({'minlen': 2, 'maxlen': 3}, 'fo'), ({'minlen': 2, 'maxlen': 3}, 'fo'),
({'minlen': 2, 'maxlen': 3}, 'foo'), ({'minlen': 2, 'maxlen': 3}, 'abc'),
# valid_values # valid_values
({'valid_values': configtypes.ValidValues('fooo')}, 'fooo'), ({'valid_values': configtypes.ValidValues('abcd')}, 'abcd'),
]) ])
def test_validate_valid(self, klass, kwargs, val): def test_validate_valid(self, klass, kwargs, val):
klass(**kwargs).validate(val) klass(**kwargs).validate(val)
@ -320,16 +320,21 @@ class TestString:
({'minlen': 2}, 'f'), ({'minlen': 2}, 'f'),
({'maxlen': 2}, 'fob'), ({'maxlen': 2}, 'fob'),
({'minlen': 2, 'maxlen': 3}, 'f'), ({'minlen': 2, 'maxlen': 3}, 'f'),
({'minlen': 2, 'maxlen': 3}, 'fooo'), ({'minlen': 2, 'maxlen': 3}, 'abcd'),
# valid_values # valid_values
({'valid_values': configtypes.ValidValues('blah')}, 'fooo'), ({'valid_values': configtypes.ValidValues('blah')}, 'abcd'),
]) ])
def test_validate_invalid(self, klass, kwargs, val): def test_validate_invalid(self, klass, kwargs, val):
with pytest.raises(configexc.ValidationError): with pytest.raises(configexc.ValidationError):
klass(**kwargs).validate(val) klass(**kwargs).validate(val)
def test_validate_duplicate_invalid(self):
typ = configtypes.UniqueCharString()
with pytest.raises(configexc.ValidationError):
typ.validate('foobar')
def test_transform(self, klass): def test_transform(self, klass):
assert klass().transform('foobar') == 'foobar' assert klass().transform('fobar') == 'fobar'
@pytest.mark.parametrize('value', [ @pytest.mark.parametrize('value', [
None, None,