mopidy/tests/config/config_test.py
Thomas Adamcik d5cb4282d9 config: Add preprocessor for preserving comments when editing configs.
Adds markers to configs files that ensures configparser won't mangle comments
in the files. Will be combined with a postprocessor that undoes these changes.
2013-10-27 11:38:01 +01:00

205 lines
7.4 KiB
Python

# encoding: utf-8
from __future__ import unicode_literals
import mock
import unittest
from mopidy import config
from tests import path_to_data_dir
class LoadConfigTest(unittest.TestCase):
def test_load_nothing(self):
self.assertEqual({}, config._load([], [], []))
def test_load_single_default(self):
default = b'[foo]\nbar = baz'
expected = {'foo': {'bar': 'baz'}}
result = config._load([], [default], [])
self.assertEqual(expected, result)
def test_unicode_default(self):
default = '[foo]\nbar = æøå'
expected = {'foo': {'bar': 'æøå'.encode('utf-8')}}
result = config._load([], [default], [])
self.assertEqual(expected, result)
def test_load_defaults(self):
default1 = b'[foo]\nbar = baz'
default2 = b'[foo2]\n'
expected = {'foo': {'bar': 'baz'}, 'foo2': {}}
result = config._load([], [default1, default2], [])
self.assertEqual(expected, result)
def test_load_single_override(self):
override = ('foo', 'bar', 'baz')
expected = {'foo': {'bar': 'baz'}}
result = config._load([], [], [override])
self.assertEqual(expected, result)
def test_load_overrides(self):
override1 = ('foo', 'bar', 'baz')
override2 = ('foo2', 'bar', 'baz')
expected = {'foo': {'bar': 'baz'}, 'foo2': {'bar': 'baz'}}
result = config._load([], [], [override1, override2])
self.assertEqual(expected, result)
def test_load_single_file(self):
file1 = path_to_data_dir('file1.conf')
expected = {'foo': {'bar': 'baz'}}
result = config._load([file1], [], [])
self.assertEqual(expected, result)
def test_load_files(self):
file1 = path_to_data_dir('file1.conf')
file2 = path_to_data_dir('file2.conf')
expected = {'foo': {'bar': 'baz'}, 'foo2': {'bar': 'baz'}}
result = config._load([file1, file2], [], [])
self.assertEqual(expected, result)
def test_load_file_with_utf8(self):
expected = {'foo': {'bar': 'æøå'.encode('utf-8')}}
result = config._load([path_to_data_dir('file3.conf')], [], [])
self.assertEqual(expected, result)
def test_load_file_with_error(self):
expected = {'foo': {'bar': 'baz'}}
result = config._load([path_to_data_dir('file4.conf')], [], [])
self.assertEqual(expected, result)
class ValidateTest(unittest.TestCase):
def setUp(self):
self.schema = config.ConfigSchema('foo')
self.schema['bar'] = config.ConfigValue()
def test_empty_config_no_schemas(self):
conf, errors = config._validate({}, [])
self.assertEqual({}, conf)
self.assertEqual({}, errors)
def test_config_no_schemas(self):
raw_config = {'foo': {'bar': 'baz'}}
conf, errors = config._validate(raw_config, [])
self.assertEqual({}, conf)
self.assertEqual({}, errors)
def test_empty_config_single_schema(self):
conf, errors = config._validate({}, [self.schema])
self.assertEqual({'foo': {'bar': None}}, conf)
self.assertEqual({'foo': {'bar': 'config key not found.'}}, errors)
def test_config_single_schema(self):
raw_config = {'foo': {'bar': 'baz'}}
conf, errors = config._validate(raw_config, [self.schema])
self.assertEqual({'foo': {'bar': 'baz'}}, conf)
self.assertEqual({}, errors)
def test_config_single_schema_config_error(self):
raw_config = {'foo': {'bar': 'baz'}}
self.schema['bar'] = mock.Mock()
self.schema['bar'].deserialize.side_effect = ValueError('bad')
conf, errors = config._validate(raw_config, [self.schema])
self.assertEqual({'foo': {'bar': None}}, conf)
self.assertEqual({'foo': {'bar': 'bad'}}, errors)
# TODO: add more tests
INPUT_CONFIG = """# comments before first section should work
[section] anything goes ; after the [] block it seems.
; this is a valid comment
this-should-equal-baz = baz ; as this is a comment
this-should-equal-everything = baz # as this is not a comment
# this is also a comment ; and the next line should be a blank comment.
;
# foo # = should all be treated as a comment.
"""
PROCESSED_CONFIG = """[__COMMENTS__]
__HASH0__ = comments before first section should work
__BLANK1__ =
[section]
__SECTION2__ = anything goes
__INLINE3__ = after the [] block it seems.
__SEMICOLON4__ = this is a valid comment
this-should-equal-baz = baz
__INLINE5__ = as this is a comment
this-should-equal-everything = baz # as this is not a comment
__BLANK6__ =
__HASH7__ = this is also a comment
__INLINE8__ = and the next line should be a blank comment.
__SEMICOLON9__ =
__HASH10__ = foo # = should all be treated as a comment."""
class ProcessorTest(unittest.TestCase):
maxDiff = None # Show entire diff.
def test_preprocessor_empty_config(self):
result = config._preprocess('')
self.assertEqual(result, '[__COMMENTS__]')
def test_preprocessor_plain_section(self):
result = config._preprocess('[section]\nfoo = bar')
self.assertEqual(result, '[__COMMENTS__]\n'
'[section]\n'
'foo = bar')
def test_preprocessor_initial_comments(self):
result = config._preprocess('; foobar')
self.assertEqual(result, '[__COMMENTS__]\n'
'__SEMICOLON0__ = foobar')
result = config._preprocess('# foobar')
self.assertEqual(result, '[__COMMENTS__]\n'
'__HASH0__ = foobar')
result = config._preprocess('; foo\n# bar')
self.assertEqual(result, '[__COMMENTS__]\n'
'__SEMICOLON0__ = foo\n'
'__HASH1__ = bar')
def test_preprocessor_initial_comment_inline_handling(self):
result = config._preprocess('; foo ; bar ; baz')
self.assertEqual(result, '[__COMMENTS__]\n'
'__SEMICOLON0__ = foo\n'
'__INLINE1__ = bar\n'
'__INLINE2__ = baz')
def test_preprocessor_inline_semicolon_comment(self):
result = config._preprocess('[section]\nfoo = bar ; baz')
self.assertEqual(result, '[__COMMENTS__]\n'
'[section]\n'
'foo = bar\n'
'__INLINE0__ = baz')
def test_preprocessor_no_inline_hash_comment(self):
result = config._preprocess('[section]\nfoo = bar # baz')
self.assertEqual(result, '[__COMMENTS__]\n'
'[section]\n'
'foo = bar # baz')
def test_preprocessor_section_extra_text(self):
result = config._preprocess('[section] foobar')
self.assertEqual(result, '[__COMMENTS__]\n'
'[section]\n'
'__SECTION0__ = foobar')
def test_preprocessor_section_extra_text_inline_semicolon(self):
result = config._preprocess('[section] foobar ; baz')
self.assertEqual(result, '[__COMMENTS__]\n'
'[section]\n'
'__SECTION0__ = foobar\n'
'__INLINE1__ = baz')
def test_preprocessor_conversion(self):
"""Tests all of the above cases at once."""
result = config._preprocess(INPUT_CONFIG)
self.assertEqual(result, PROCESSED_CONFIG)