diff --git a/mopidy/config/types.py b/mopidy/config/types.py index 6543b62e..c43da740 100644 --- a/mopidy/config/types.py +++ b/mopidy/config/types.py @@ -80,23 +80,36 @@ class String(ConfigValue): return value def serialize(self, value): + if value is None: + return b'' return encode(value) class Secret(ConfigValue): - """String value. + """Secret value. - Masked when being displayed, and is not decoded. + Should be used for passwords, auth tokens etc. Deserializing will not + convert to unicode. Will mask value when being displayed. """ def __init__(self, optional=False, choices=None): self._required = not optional def deserialize(self, value): + value = value.strip() validators.validate_required(value, self._required) + if not value: + return None + return value + + def serialize(self, value): + if value is None: + return b'' return value def format(self, value): - return '********' + if value is None: + return b'' + return b'********' class Integer(ConfigValue): diff --git a/tests/config/types_test.py b/tests/config/types_test.py index fe616b77..a5f2c9dc 100644 --- a/tests/config/types_test.py +++ b/tests/config/types_test.py @@ -88,6 +88,12 @@ class StringTest(unittest.TestCase): self.assertIsInstance(result, bytes) self.assertEqual(r'a\n\tb'.encode('utf-8'), result) + def test_serialize_none(self): + value = types.String() + result = value.serialize(None) + self.assertIsInstance(result, bytes) + self.assertEqual(b'', result) + class SecretTest(unittest.TestCase): def test_deserialize_passes_through(self): @@ -100,13 +106,28 @@ class SecretTest(unittest.TestCase): value = types.Secret() self.assertRaises(ValueError, value.deserialize, b'') - def test_serialize_conversion_to_string(self): + def test_deserialize_respects_optional(self): + value = types.Secret(optional=True) + self.assertIsNone(value.deserialize(b'')) + self.assertIsNone(value.deserialize(b' ')) + + def test_serialize_none(self): value = types.Secret() - self.assertIsInstance(value.serialize(object()), bytes) + result = value.serialize(None) + self.assertIsInstance(result, bytes) + self.assertEqual(b'', result) def test_format_masks_value(self): value = types.Secret() - self.assertEqual('********', value.format('s3cret')) + result = value.format('s3cret') + self.assertIsInstance(result, bytes) + self.assertEqual(b'********', result) + + def test_format_none(self): + value = types.Secret() + result = value.format(None) + self.assertIsInstance(result, bytes) + self.assertEqual(b'', result) class IntegerTest(unittest.TestCase):