From 0f4e1bafda72b3493b0c85c1ff351b1f5350157b Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 5 Aug 2014 13:39:01 +0400 Subject: [PATCH] Refactor config_mock module to not use globals and fix tests --- tests/lib/config_mock.py | 141 ++++++++------ tests/test_cmdline.py | 3 +- tests/test_config_merging.py | 2 + tests/test_config_reload.py | 344 +++++++++++++++++------------------ tests/test_configuration.py | 322 ++++++++++++++++---------------- 5 files changed, 420 insertions(+), 392 deletions(-) diff --git a/tests/lib/config_mock.py b/tests/lib/config_mock.py index 35eaf0cd..55f206d1 100644 --- a/tests/lib/config_mock.py +++ b/tests/lib/config_mock.py @@ -3,37 +3,53 @@ from threading import Lock from powerline.renderer import Renderer from powerline.lib.config import ConfigLoader from powerline import Powerline +from tests.lib import Args, replace_attr from copy import deepcopy from time import sleep from functools import wraps +import os -access_log = [] -access_lock = Lock() +class TestHelpers(object): + def __init__(self, config): + self.config = config + self.access_log = [] + self.access_lock = Lock() + def loader_condition(self, path): + return (path in self.config) and path -def load_json_config(config_file_path, *args, **kwargs): - global access_log - with access_lock: - access_log.append(config_file_path) - try: - return deepcopy(config_container['config'][config_file_path]) - except KeyError: - raise IOError(config_file_path) + def find_config_files(self, cfg_path, config_loader, loader_callback): + if cfg_path.endswith('.json'): + cfg_path = cfg_path[:-5] + if cfg_path.startswith('/'): + cfg_path = cfg_path.lstrip('/') + with self.access_lock: + self.access_log.append('check:' + cfg_path) + if cfg_path in self.config: + yield cfg_path + else: + if config_loader: + config_loader.register_missing(self.loader_condition, loader_callback, cfg_path) + raise IOError(('fcf:' if cfg_path.endswith('raise') else '') + cfg_path) + def load_json_config(self, config_file_path, *args, **kwargs): + if config_file_path.endswith('.json'): + config_file_path = config_file_path[:-5] + if config_file_path.startswith('/'): + config_file_path = config_file_path.lstrip('/') + with self.access_lock: + self.access_log.append('load:' + config_file_path) + try: + return deepcopy(self.config[config_file_path]) + except KeyError: + raise IOError(config_file_path) -def _find_config_file(config, search_paths, config_file): - if config_file.endswith('raise') and config_file not in config: - raise IOError('fcf:' + config_file) - return config_file - - -def pop_events(): - global access_log - with access_lock: - r = access_log[:] - access_log = [] - return r + def pop_events(self): + with self.access_lock: + r = self.access_log[:] + self.access_log = [] + return r def log_call(func): @@ -44,7 +60,7 @@ def log_call(func): return ret -class Watcher(object): +class TestWatcher(object): events = set() lock = Lock() @@ -109,20 +125,46 @@ class EvenSimplerRenderer(Renderer): class TestPowerline(Powerline): _created = False + def __init__(self, _helpers, **kwargs): + super(TestPowerline, self).__init__(**kwargs) + self._helpers = _helpers + self.find_config_files = _helpers.find_config_files + @staticmethod def get_local_themes(local_themes): return local_themes + @staticmethod + def get_config_paths(): + return [''] + def _will_create_renderer(self): return self.cr_kwargs + def _pop_events(self): + return self._helpers.pop_events() + renderer = EvenSimplerRenderer -def get_powerline(**kwargs): +class TestConfigLoader(ConfigLoader): + def __init__(self, _helpers, **kwargs): + watcher = TestWatcher() + super(TestConfigLoader, self).__init__( + load=_helpers.load_json_config, + watcher=watcher, + watcher_type='test', + **kwargs + ) + + +def get_powerline(config, **kwargs): + helpers = TestHelpers(config) return get_powerline_raw( + helpers, TestPowerline, + _helpers=helpers, ext='test', renderer_module='tests.lib.config_mock', logger=Logger(), @@ -130,45 +172,42 @@ def get_powerline(**kwargs): ) -def get_powerline_raw(PowerlineClass, **kwargs): +def select_renderer(simpler_renderer=False): global renderer - watcher = Watcher() - if kwargs.pop('simpler_renderer', False): - renderer = EvenSimplerRenderer - else: - renderer = SimpleRenderer + renderer = EvenSimplerRenderer if simpler_renderer else SimpleRenderer + + +def get_powerline_raw(helpers, PowerlineClass, **kwargs): + if not isinstance(helpers, TestHelpers): + helpers = TestHelpers(helpers) + select_renderer(kwargs.pop('simpler_renderer', False)) pl = PowerlineClass( - config_loader=ConfigLoader( - load=load_json_config, - watcher=watcher, - watcher_type='test', + config_loader=TestConfigLoader( + _helpers=helpers, run_once=kwargs.get('run_once') ), **kwargs ) - pl._watcher = watcher + pl._watcher = pl.config_loader.watcher return pl -config_container = None - - -def swap_attributes(cfg_container, powerline_module, replaces): - global config_container - config_container = cfg_container - if not replaces: - replaces = { - '_find_config_file': lambda *args: _find_config_file(config_container['config'], *args), - } - for attr, val in replaces.items(): - old_val = getattr(powerline_module, attr) - setattr(powerline_module, attr, val) - replaces[attr] = old_val - return replaces +def swap_attributes(config, powerline_module): + return replace_attr(powerline_module, 'os', Args( + path=Args( + isfile=lambda path: path.lstrip('/').replace('.json', '') in config, + join=os.path.join, + expanduser=lambda path: path, + realpath=lambda path: path, + dirname=os.path.dirname, + ), + environ={}, + )) def add_watcher_events(p, *args, **kwargs): - p._watcher._reset(args) + if isinstance(p._watcher, TestWatcher): + p._watcher._reset(args) while not p._will_create_renderer(): sleep(kwargs.get('interval', 0.1)) if not kwargs.get('wait', True): diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py index 9895709f..f1ff683a 100644 --- a/tests/test_cmdline.py +++ b/tests/test_cmdline.py @@ -71,6 +71,7 @@ class TestParser(TestCase): '-c', 'common.spaces=4', '-t', 'default.segment_data.hostname.before=H:', '-p', '.', + '-p', '..', '-R', 'smth={"abc":"def"}', ], { 'ext': ['shell'], @@ -90,7 +91,7 @@ class TestParser(TestCase): } } }, - 'config_path': ['.'], + 'config_path': ['.', '..'], 'renderer_arg': {'smth': {'abc': 'def'}}, }), (['shell', '-R', 'arg=true'], {'ext': ['shell'], 'renderer_arg': {'arg': True}}), diff --git a/tests/test_config_merging.py b/tests/test_config_merging.py index 1c8d5071..7941e148 100644 --- a/tests/test_config_merging.py +++ b/tests/test_config_merging.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from powerline import Powerline from tests import TestCase +from tests.lib.config_mock import select_renderer from shutil import rmtree import os import json @@ -114,6 +115,7 @@ class WithConfigTree(object): mkdir_recursive(os.path.dirname(fname)) with open(fname, 'w') as F: json.dump(v, F) + select_renderer(simpler_renderer=True) self.p = TestPowerline( ext='test', renderer_module='tests.lib.config_mock', diff --git a/tests/test_config_reload.py b/tests/test_config_reload.py index cc6f331d..8deb0d1a 100644 --- a/tests/test_config_reload.py +++ b/tests/test_config_reload.py @@ -1,11 +1,12 @@ # vim:fileencoding=utf-8:noet from __future__ import unicode_literals -import powerline as powerline_module + from time import sleep -from tests import TestCase -from tests.lib import replace_item -from tests.lib.config_mock import swap_attributes, get_powerline, pop_events, add_watcher_events from copy import deepcopy +from functools import wraps + +from tests import TestCase +from tests.lib.config_mock import get_powerline, add_watcher_events config = { @@ -93,201 +94,192 @@ config = { } +def with_new_config(func): + @wraps(func) + def f(self): + return func(self, deepcopy(config)) + return f + + class TestConfigReload(TestCase): - def assertAccessEvents(self, *args): - self.assertEqual(set(pop_events()), set(args)) + def assertAccessEvents(self, p, *args): + events = set() + for event in args: + if ':' not in event: + events.add('check:' + event) + events.add('load:' + event) + else: + events.add(event) + self.assertEqual(set(p._pop_events()), events) - def test_noreload(self): - with get_powerline(run_once=True) as p: - with replace_item(globals(), 'config', deepcopy(config)): - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('config', 'colors', 'colorschemes/default', 'colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') - config['config']['common']['spaces'] = 1 - add_watcher_events(p, 'config', wait=False, interval=0.05) - # When running once thread should not start - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents() - self.assertEqual(p.logger._pop_msgs(), []) - # Without the following assertion test_reload_colors may fail for - # unknown reason (with AssertionError telling about “config” accessed - # one more time then needed) - pop_events() + @with_new_config + def test_noreload(self, config): + with get_powerline(config, run_once=True) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') + config['config']['common']['spaces'] = 1 + add_watcher_events(p, 'config', wait=False, interval=0.05) + # When running once thread should not start + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p) + self.assertEqual(p.logger._pop_msgs(), []) - def test_reload_main(self): - with get_powerline(run_once=False) as p: - with replace_item(globals(), 'config', deepcopy(config)): - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('config', 'colors', 'colorschemes/default', 'colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') + @with_new_config + def test_reload_main(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') - config['config']['common']['spaces'] = 1 - add_watcher_events(p, 'config') - self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') - self.assertAccessEvents('config') - self.assertEqual(p.logger._pop_msgs(), []) + config['config']['common']['spaces'] = 1 + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') + self.assertAccessEvents(p, 'config') + self.assertEqual(p.logger._pop_msgs(), []) - config['config']['ext']['test']['theme'] = 'nonexistent' - add_watcher_events(p, 'config') - self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') - self.assertAccessEvents('config', 'themes/test/nonexistent') - # It should normally handle file missing error - self.assertEqual(p.logger._pop_msgs(), ['exception:test:powerline:Failed to create renderer: themes/test/nonexistent']) + config['config']['ext']['test']['theme'] = 'nonexistent' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') + self.assertAccessEvents(p, 'config', 'check:themes/test/nonexistent') + # It should normally handle file missing error + self.assertEqual(p.logger._pop_msgs(), ['exception:test:powerline:Failed to create renderer: themes/test/nonexistent']) - config['config']['ext']['test']['theme'] = 'default' - add_watcher_events(p, 'config') - self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') - self.assertAccessEvents('config', 'themes/test/default') - self.assertEqual(p.logger._pop_msgs(), []) + config['config']['ext']['test']['theme'] = 'default' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') + self.assertAccessEvents(p, 'config', 'themes/test/default') + self.assertEqual(p.logger._pop_msgs(), []) - config['config']['ext']['test']['colorscheme'] = 'nonexistent' - add_watcher_events(p, 'config') - self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') - self.assertAccessEvents('config', 'colorschemes/nonexistent', 'colorschemes/test/__main__', 'colorschemes/test/nonexistent') - # It should normally handle file missing error - self.assertEqual(p.logger._pop_msgs(), [ - 'exception:test:powerline:Failed to load colorscheme: colorschemes/nonexistent', - 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/__main__', - 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/nonexistent', - 'exception:test:powerline:Failed to create renderer: colorschemes/test/nonexistent' - ]) + config['config']['ext']['test']['colorscheme'] = 'nonexistent' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<1 2 1> s <2 4 False>>><3 4 4>g <4 False False>>>') + self.assertAccessEvents(p, 'config', 'check:colorschemes/nonexistent', 'check:colorschemes/test/__main__', 'check:colorschemes/test/nonexistent') + # It should normally handle file missing error + self.assertEqual(p.logger._pop_msgs(), [ + 'exception:test:powerline:Failed to load colorscheme: colorschemes/nonexistent', + 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/__main__', + 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/nonexistent', + 'exception:test:powerline:Failed to create renderer: colorschemes/test/nonexistent' + ]) - config['config']['ext']['test']['colorscheme'] = '2' - add_watcher_events(p, 'config') - self.assertEqual(p.render(), '<2 3 1> s <3 4 False>>><1 4 4>g <4 False False>>>') - self.assertAccessEvents('config', 'colorschemes/2', 'colorschemes/test/__main__', 'colorschemes/test/2') - self.assertEqual(p.logger._pop_msgs(), []) + config['config']['ext']['test']['colorscheme'] = '2' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<2 3 1> s <3 4 False>>><1 4 4>g <4 False False>>>') + self.assertAccessEvents(p, 'config', 'check:colorschemes/2', 'check:colorschemes/test/__main__', 'colorschemes/test/2') + self.assertEqual(p.logger._pop_msgs(), []) - config['config']['ext']['test']['theme'] = '2' - add_watcher_events(p, 'config') - self.assertEqual(p.render(), '<2 3 1> t <3 4 False>>><1 4 4>b <4 False False>>>') - self.assertAccessEvents('config', 'themes/test/2') - self.assertEqual(p.logger._pop_msgs(), []) + config['config']['ext']['test']['theme'] = '2' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<2 3 1> t <3 4 False>>><1 4 4>b <4 False False>>>') + self.assertAccessEvents(p, 'config', 'themes/test/2') + self.assertEqual(p.logger._pop_msgs(), []) - self.assertEqual(p.renderer.local_themes, None) - config['config']['ext']['test']['local_themes'] = 'something' - add_watcher_events(p, 'config') - self.assertEqual(p.render(), '<2 3 1> t <3 4 False>>><1 4 4>b <4 False False>>>') - self.assertAccessEvents('config') - self.assertEqual(p.logger._pop_msgs(), []) - self.assertEqual(p.renderer.local_themes, 'something') - pop_events() + self.assertEqual(p.renderer.local_themes, None) + config['config']['ext']['test']['local_themes'] = 'something' + add_watcher_events(p, 'config') + self.assertEqual(p.render(), '<2 3 1> t <3 4 False>>><1 4 4>b <4 False False>>>') + self.assertAccessEvents(p, 'config') + self.assertEqual(p.logger._pop_msgs(), []) + self.assertEqual(p.renderer.local_themes, 'something') - def test_reload_unexistent(self): - with get_powerline(run_once=False) as p: - with replace_item(globals(), 'config', deepcopy(config)): - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('config', 'colors', 'colorschemes/default', 'colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') + @with_new_config + def test_reload_unexistent(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') - config['config']['ext']['test']['colorscheme'] = 'nonexistentraise' - add_watcher_events(p, 'config') - # It may appear that p.logger._pop_msgs() is called after given - # exception is added to the mesagges, but before config_loader - # exception was added (this one: - # “exception:test:config_loader:Error while running condition - # function for key colorschemes/test/nonexistentraise: - # fcf:colorschemes/test/nonexistentraise”). - # sleep(0.1) - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - # For colorschemes/{test/,}*raise find_config_file raises - # IOError, but it does not do so for colorschemes/test/__main__, - # so powerline is trying to load this, but not other - # colorschemes/* - self.assertAccessEvents('config', 'colorschemes/test/__main__') - self.assertIn('exception:test:powerline:Failed to create renderer: fcf:colorschemes/test/nonexistentraise', p.logger._pop_msgs()) + config['config']['ext']['test']['colorscheme'] = 'nonexistentraise' + add_watcher_events(p, 'config') + # It may appear that p.logger._pop_msgs() is called after given + # exception is added to the mesagges, but before config_loader + # exception was added (this one: + # “exception:test:config_loader:Error while running condition + # function for key colorschemes/test/nonexistentraise: + # fcf:colorschemes/test/nonexistentraise”). + # sleep(0.1) + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + # For colorschemes/{test/,}*raise find_config_file raises + # IOError, but it does not do so for check:colorschemes/test/__main__, + # so powerline is trying to load this, but not other + # colorschemes/* + self.assertAccessEvents(p, 'config', 'check:colorschemes/test/__main__', 'check:colorschemes/nonexistentraise', 'check:colorschemes/test/nonexistentraise') + self.assertIn('exception:test:powerline:Failed to create renderer: fcf:colorschemes/test/nonexistentraise', p.logger._pop_msgs()) - config['colorschemes/nonexistentraise'] = {} - config['colorschemes/test/nonexistentraise'] = { - 'groups': { - "str1": {"fg": "col1", "bg": "col3", "attr": ["bold"]}, - "str2": {"fg": "col2", "bg": "col4", "attr": ["underline"]}, - }, - } - while not p._will_create_renderer(): - sleep(0.1) - self.assertEqual(p.render(), '<1 3 1> s<3 4 False>>><2 4 4>g<4 False False>>>') - # Same as above - self.assertAccessEvents('colorschemes/nonexistentraise', 'colorschemes/test/nonexistentraise', 'colorschemes/test/__main__') - self.assertEqual(p.logger._pop_msgs(), []) - pop_events() + config['colorschemes/nonexistentraise'] = {} + config['colorschemes/test/nonexistentraise'] = { + 'groups': { + "str1": {"fg": "col1", "bg": "col3", "attr": ["bold"]}, + "str2": {"fg": "col2", "bg": "col4", "attr": ["underline"]}, + }, + } + while not p._will_create_renderer(): + sleep(0.1) + self.assertEqual(p.render(), '<1 3 1> s<3 4 False>>><2 4 4>g<4 False False>>>') + # Same as above + self.assertAccessEvents(p, 'colorschemes/nonexistentraise', 'colorschemes/test/nonexistentraise', 'check:colorschemes/test/__main__') + self.assertEqual(p.logger._pop_msgs(), []) - def test_reload_colors(self): - with get_powerline(run_once=False) as p: - with replace_item(globals(), 'config', deepcopy(config)): - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('config', 'colors', 'colorschemes/default', 'colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') + @with_new_config + def test_reload_colors(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') - config['colors']['colors']['col1'] = 5 - add_watcher_events(p, 'colors') - self.assertEqual(p.render(), '<5 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('colors') - self.assertEqual(p.logger._pop_msgs(), []) - pop_events() + config['colors']['colors']['col1'] = 5 + add_watcher_events(p, 'colors') + self.assertEqual(p.render(), '<5 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'colors') + self.assertEqual(p.logger._pop_msgs(), []) - def test_reload_colorscheme(self): - with get_powerline(run_once=False) as p: - with replace_item(globals(), 'config', deepcopy(config)): - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('config', 'colors', 'colorschemes/default', 'colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') + @with_new_config + def test_reload_colorscheme(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') - config['colorschemes/test/default']['groups']['str1']['bg'] = 'col3' - add_watcher_events(p, 'colorschemes/test/default') - self.assertEqual(p.render(), '<1 3 1> s<3 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('colorschemes/default', 'colorschemes/test/__main__', 'colorschemes/test/default') - self.assertEqual(p.logger._pop_msgs(), []) - pop_events() + config['colorschemes/test/default']['groups']['str1']['bg'] = 'col3' + add_watcher_events(p, 'colorschemes/test/default') + self.assertEqual(p.render(), '<1 3 1> s<3 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default') + self.assertEqual(p.logger._pop_msgs(), []) - def test_reload_theme(self): - with get_powerline(run_once=False) as p: - with replace_item(globals(), 'config', deepcopy(config)): - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('config', 'colors', 'colorschemes/default', 'colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') + @with_new_config + def test_reload_theme(self, config): + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') - config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' - add_watcher_events(p, 'themes/test/default') - self.assertEqual(p.render(), '<1 2 1> col3<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('themes/test/default') - self.assertEqual(p.logger._pop_msgs(), []) - pop_events() + config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' + add_watcher_events(p, 'themes/test/default') + self.assertEqual(p.render(), '<1 2 1> col3<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'themes/test/default') + self.assertEqual(p.logger._pop_msgs(), []) - def test_reload_theme_main(self): - with replace_item(globals(), 'config', deepcopy(config)): - config['config']['common']['interval'] = None - with get_powerline(run_once=False) as p: - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('config', 'colors', 'colorschemes/default', 'colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') + @with_new_config + def test_reload_theme_main(self, config): + config['config']['common']['interval'] = None + with get_powerline(config, run_once=False) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') - config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' - add_watcher_events(p, 'themes/test/default', wait=False) - self.assertEqual(p.render(), '<1 2 1> col3<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('themes/test/default') - self.assertEqual(p.logger._pop_msgs(), []) - self.assertTrue(p._watcher._calls) - pop_events() + config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' + add_watcher_events(p, 'themes/test/default', wait=False) + self.assertEqual(p.render(), '<1 2 1> col3<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'themes/test/default') + self.assertEqual(p.logger._pop_msgs(), []) + self.assertTrue(p._watcher._calls) - def test_run_once_no_theme_reload(self): - with replace_item(globals(), 'config', deepcopy(config)): - config['config']['common']['interval'] = None - with get_powerline(run_once=True) as p: - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents('config', 'colors', 'colorschemes/default', 'colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') + @with_new_config + def test_run_once_no_theme_reload(self, config): + config['config']['common']['interval'] = None + with get_powerline(config, run_once=True) as p: + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p, 'config', 'colors', 'check:colorschemes/default', 'check:colorschemes/test/__main__', 'colorschemes/test/default', 'themes/test/default') - config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' - add_watcher_events(p, 'themes/test/default', wait=False) - self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') - self.assertAccessEvents() - self.assertEqual(p.logger._pop_msgs(), []) - self.assertEqual(p._watcher._calls, []) - pop_events() - - -replaces = {} - - -def setUpModule(): - global replaces - replaces = swap_attributes(globals(), powerline_module, replaces) - - -tearDownModule = setUpModule + config['themes/test/default']['segments']['left'][0]['contents'] = 'col3' + add_watcher_events(p, 'themes/test/default', wait=False) + self.assertEqual(p.render(), '<1 2 1> s<2 4 False>>><3 4 4>g<4 False False>>>') + self.assertAccessEvents(p) + self.assertEqual(p.logger._pop_msgs(), []) if __name__ == '__main__': diff --git a/tests/test_configuration.py b/tests/test_configuration.py index faf355b5..a1d6b836 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -1,11 +1,8 @@ # vim:fileencoding=utf-8:noet from __future__ import unicode_literals, absolute_import, division import tests.vim as vim_module -import powerline as powerline_module from tests import TestCase -from tests.lib import replace_item -from tests.lib.config_mock import swap_attributes, get_powerline -from tests.lib.config_mock import get_powerline_raw +from tests.lib.config_mock import get_powerline, get_powerline_raw, swap_attributes from functools import wraps from copy import deepcopy import sys @@ -123,11 +120,19 @@ config = { } -def add_p_arg(func): +def with_new_config(func): @wraps(func) def f(self): - with get_powerline(run_once=True, simpler_renderer=True) as p: - func(self, p) + return func(self, deepcopy(config)) + return f + + +def add_args(func): + @wraps(func) + def f(self): + new_config = deepcopy(config) + with get_powerline(new_config, run_once=True, simpler_renderer=True) as p: + func(self, p, new_config) return f @@ -140,166 +145,158 @@ class TestRender(TestCase): class TestLines(TestRender): - @add_p_arg - def test_without_above(self, p): + @add_args + def test_without_above(self, p, config): self.assertRenderEqual(p, '{121} s{24}>>{344}g{34}>{34}<{344}f {--}') self.assertRenderEqual(p, '{121} s {24}>>{344}g{34}>{34}<{344}f {--}', width=10) # self.assertRenderEqual(p, '{121} s {24}>>{344}g{34}>{34}<{344} f {--}', width=11) self.assertEqual(list(p.render_above_lines()), []) - def test_with_above(self): - with replace_item(globals(), 'config', deepcopy(config)): - old_segments = deepcopy(config['themes/test/default']['segments']) - config['themes/test/default']['segments']['above'] = [old_segments] - with get_powerline(run_once=True, simpler_renderer=True) as p: - self.assertRenderLinesEqual(p, [ - '{121} s{24}>>{344}g{34}>{34}<{344}f {--}', - ]) - self.assertRenderLinesEqual(p, [ - '{121} s {24}>>{344}g{34}>{34}<{344}f {--}', - ], width=10) + @with_new_config + def test_with_above(self, config): + old_segments = deepcopy(config['themes/test/default']['segments']) + config['themes/test/default']['segments']['above'] = [old_segments] + with get_powerline(config, run_once=True, simpler_renderer=True) as p: + self.assertRenderLinesEqual(p, [ + '{121} s{24}>>{344}g{34}>{34}<{344}f {--}', + ]) + self.assertRenderLinesEqual(p, [ + '{121} s {24}>>{344}g{34}>{34}<{344}f {--}', + ], width=10) - config['themes/test/default']['segments']['above'] = [old_segments] * 2 - with get_powerline(run_once=True, simpler_renderer=True) as p: - self.assertRenderLinesEqual(p, [ - '{121} s{24}>>{344}g{34}>{34}<{344}f {--}', - '{121} s{24}>>{344}g{34}>{34}<{344}f {--}', - ]) - self.assertRenderLinesEqual(p, [ - '{121} s {24}>>{344}g{34}>{34}<{344}f {--}', - '{121} s {24}>>{344}g{34}>{34}<{344}f {--}', - ], width=10) + config['themes/test/default']['segments']['above'] = [old_segments] * 2 + with get_powerline(config, run_once=True, simpler_renderer=True) as p: + self.assertRenderLinesEqual(p, [ + '{121} s{24}>>{344}g{34}>{34}<{344}f {--}', + '{121} s{24}>>{344}g{34}>{34}<{344}f {--}', + ]) + self.assertRenderLinesEqual(p, [ + '{121} s {24}>>{344}g{34}>{34}<{344}f {--}', + '{121} s {24}>>{344}g{34}>{34}<{344}f {--}', + ], width=10) class TestSegments(TestRender): - @add_p_arg - def test_display(self, p): - with replace_item(globals(), 'config', deepcopy(config)): - config['themes/test/default']['segments']['left'][0]['display'] = False - config['themes/test/default']['segments']['left'][1]['display'] = True - config['themes/test/default']['segments']['right'][0]['display'] = False - self.assertRenderEqual(p, '{344} g{4-}>>{--}') + @add_args + def test_display(self, p, config): + config['themes/test/default']['segments']['left'][0]['display'] = False + config['themes/test/default']['segments']['left'][1]['display'] = True + config['themes/test/default']['segments']['right'][0]['display'] = False + self.assertRenderEqual(p, '{344} g{4-}>>{--}') class TestColorschemesHierarchy(TestRender): - @add_p_arg - def test_group_redirects(self, p): - with replace_item(globals(), 'config', deepcopy(config)): - config['themes/test/default']['segments'] = { - 'left': [ - highlighted_string('a', 'd1', draw_hard_divider=False), - highlighted_string('b', 'd2', draw_hard_divider=False), - highlighted_string('c', 'd3', draw_hard_divider=False), - highlighted_string('A', 'm1', draw_hard_divider=False), - highlighted_string('B', 'm2', draw_hard_divider=False), - highlighted_string('C', 'm3', draw_hard_divider=False), - highlighted_string('1', 'g1', draw_hard_divider=False), - highlighted_string('2', 'g2', draw_hard_divider=False), - highlighted_string('3', 'g3', draw_hard_divider=False), - ], - 'right': [], - } - self.assertRenderEqual(p, '{78} a{910}b{1112}c{56}A{910}B{1112}C{56}1{78}2{910}3{--}') - self.assertEqual(p.logger._pop_msgs(), []) + @add_args + def test_group_redirects(self, p, config): + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('a', 'd1', draw_hard_divider=False), + highlighted_string('b', 'd2', draw_hard_divider=False), + highlighted_string('c', 'd3', draw_hard_divider=False), + highlighted_string('A', 'm1', draw_hard_divider=False), + highlighted_string('B', 'm2', draw_hard_divider=False), + highlighted_string('C', 'm3', draw_hard_divider=False), + highlighted_string('1', 'g1', draw_hard_divider=False), + highlighted_string('2', 'g2', draw_hard_divider=False), + highlighted_string('3', 'g3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{78} a{910}b{1112}c{56}A{910}B{1112}C{56}1{78}2{910}3{--}') + self.assertEqual(p.logger._pop_msgs(), []) - @add_p_arg - def test_group_redirects_no_main(self, p): - with replace_item(globals(), 'config', deepcopy(config)): - del config['colorschemes/test/__main__'] - config['themes/test/default']['segments'] = { - 'left': [ - highlighted_string('a', 'd1', draw_hard_divider=False), - highlighted_string('1', 'g1', draw_hard_divider=False), - highlighted_string('2', 'g2', draw_hard_divider=False), - highlighted_string('3', 'g3', draw_hard_divider=False), - ], - 'right': [], - } - self.assertRenderEqual(p, '{78} a{56}1{78}2{910}3{--}') - self.assertEqual(p.logger._pop_msgs(), []) + @add_args + def test_group_redirects_no_main(self, p, config): + del config['colorschemes/test/__main__'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('a', 'd1', draw_hard_divider=False), + highlighted_string('1', 'g1', draw_hard_divider=False), + highlighted_string('2', 'g2', draw_hard_divider=False), + highlighted_string('3', 'g3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{78} a{56}1{78}2{910}3{--}') + self.assertEqual(p.logger._pop_msgs(), []) - @add_p_arg - def test_group_redirects_no_top_default(self, p): - with replace_item(globals(), 'config', deepcopy(config)): - del config['colorschemes/default'] - config['themes/test/default']['segments'] = { - 'left': [ - highlighted_string('c', 'd3', draw_soft_divider=False), - highlighted_string('C', 'm3', draw_hard_divider=False), - ], - 'right': [], - } - self.assertRenderEqual(p, '{1112} c{1112}C{--}') - self.assertEqual(p.logger._pop_msgs(), []) + @add_args + def test_group_redirects_no_top_default(self, p, config): + del config['colorschemes/default'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('c', 'd3', draw_soft_divider=False), + highlighted_string('C', 'm3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{1112} c{1112}C{--}') + self.assertEqual(p.logger._pop_msgs(), []) - @add_p_arg - def test_group_redirects_no_test_default(self, p): - with replace_item(globals(), 'config', deepcopy(config)): - del config['colorschemes/test/default'] - config['themes/test/default']['segments'] = { - 'left': [ - highlighted_string('A', 'm1', draw_hard_divider=False), - highlighted_string('B', 'm2', draw_hard_divider=False), - highlighted_string('C', 'm3', draw_hard_divider=False), - highlighted_string('1', 'g1', draw_hard_divider=False), - highlighted_string('2', 'g2', draw_hard_divider=False), - highlighted_string('3', 'g3', draw_hard_divider=False), - ], - 'right': [], - } - self.assertRenderEqual(p, '{56} A{910}B{1112}C{56}1{78}2{910}3{--}') - self.assertEqual(p.logger._pop_msgs(), []) + @add_args + def test_group_redirects_no_test_default(self, p, config): + del config['colorschemes/test/default'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('A', 'm1', draw_hard_divider=False), + highlighted_string('B', 'm2', draw_hard_divider=False), + highlighted_string('C', 'm3', draw_hard_divider=False), + highlighted_string('1', 'g1', draw_hard_divider=False), + highlighted_string('2', 'g2', draw_hard_divider=False), + highlighted_string('3', 'g3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{56} A{910}B{1112}C{56}1{78}2{910}3{--}') + self.assertEqual(p.logger._pop_msgs(), []) - @add_p_arg - def test_group_redirects_only_main(self, p): - with replace_item(globals(), 'config', deepcopy(config)): - del config['colorschemes/default'] - del config['colorschemes/test/default'] - config['themes/test/default']['segments'] = { - 'left': [ - highlighted_string('C', 'm3', draw_hard_divider=False), - ], - 'right': [], - } - # Powerline is not able to work without default colorscheme - # somewhere, thus it will output error string - self.assertRenderEqual(p, 'colorschemes/test/default') - self.assertEqual(p.logger._pop_msgs(), [ - 'exception:test:powerline:Failed to load colorscheme: colorschemes/default', - 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/default', - 'exception:test:powerline:Failed to create renderer: colorschemes/test/default', - 'exception:test:powerline:Failed to render: colorschemes/test/default', - ]) + @add_args + def test_group_redirects_only_main(self, p, config): + del config['colorschemes/default'] + del config['colorschemes/test/default'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('C', 'm3', draw_hard_divider=False), + ], + 'right': [], + } + # Powerline is not able to work without default colorscheme + # somewhere, thus it will output error string + self.assertRenderEqual(p, 'colorschemes/test/default') + self.assertEqual(p.logger._pop_msgs(), [ + 'exception:test:powerline:Failed to load colorscheme: colorschemes/default', + 'exception:test:powerline:Failed to load colorscheme: colorschemes/test/default', + 'exception:test:powerline:Failed to create renderer: colorschemes/test/default', + 'exception:test:powerline:Failed to render: colorschemes/test/default', + ]) - @add_p_arg - def test_group_redirects_only_top_default(self, p): - with replace_item(globals(), 'config', deepcopy(config)): - del config['colorschemes/test/__main__'] - del config['colorschemes/test/default'] - config['themes/test/default']['segments'] = { - 'left': [ - highlighted_string('1', 'g1', draw_hard_divider=False), - highlighted_string('2', 'g2', draw_hard_divider=False), - highlighted_string('3', 'g3', draw_hard_divider=False), - ], - 'right': [], - } - self.assertRenderEqual(p, '{56} 1{78}2{910}3{--}') - self.assertEqual(p.logger._pop_msgs(), []) + @add_args + def test_group_redirects_only_top_default(self, p, config): + del config['colorschemes/test/__main__'] + del config['colorschemes/test/default'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('1', 'g1', draw_hard_divider=False), + highlighted_string('2', 'g2', draw_hard_divider=False), + highlighted_string('3', 'g3', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{56} 1{78}2{910}3{--}') + self.assertEqual(p.logger._pop_msgs(), []) - @add_p_arg - def test_group_redirects_only_test_default(self, p): - with replace_item(globals(), 'config', deepcopy(config)): - del config['colorschemes/default'] - del config['colorschemes/test/__main__'] - config['themes/test/default']['segments'] = { - 'left': [ - highlighted_string('s', 'str1', draw_hard_divider=False), - ], - 'right': [], - } - self.assertRenderEqual(p, '{121} s{--}') - self.assertEqual(p.logger._pop_msgs(), []) + @add_args + def test_group_redirects_only_test_default(self, p, config): + del config['colorschemes/default'] + del config['colorschemes/test/__main__'] + config['themes/test/default']['segments'] = { + 'left': [ + highlighted_string('s', 'str1', draw_hard_divider=False), + ], + 'right': [], + } + self.assertRenderEqual(p, '{121} s{--}') + self.assertEqual(p.logger._pop_msgs(), []) class TestVim(TestCase): @@ -307,28 +304,25 @@ class TestVim(TestCase): # Regression test: test that segment obtains environment from vim, not # from os.environ. from powerline.vim import VimPowerline - with vim_module._with('environ', TEST='abc'): - with get_powerline_raw(VimPowerline) as powerline: - window = vim_module.current.window - window_id = 1 - winnr = window.number - self.assertEqual(powerline.render(window, window_id, winnr), '%#Pl_3_8404992_4_192_underline#\xa0abc%#Pl_4_192_NONE_None_NONE#>>') - vim_module._environ['TEST'] = 'def' - self.assertEqual(powerline.render(window, window_id, winnr), '%#Pl_3_8404992_4_192_underline#\xa0def%#Pl_4_192_NONE_None_NONE#>>') - - -replaces = {} + import powerline as powerline_module + import vim + vim.vars['powerline_config_path'] = '/' + with swap_attributes(config, powerline_module): + with vim_module._with('environ', TEST='abc'): + with get_powerline_raw(config, VimPowerline) as powerline: + window = vim_module.current.window + window_id = 1 + winnr = window.number + self.assertEqual(powerline.render(window, window_id, winnr), '%#Pl_3_8404992_4_192_underline#\xa0abc%#Pl_4_192_NONE_None_NONE#>>') + vim_module._environ['TEST'] = 'def' + self.assertEqual(powerline.render(window, window_id, winnr), '%#Pl_3_8404992_4_192_underline#\xa0def%#Pl_4_192_NONE_None_NONE#>>') def setUpModule(): - global replaces - replaces = swap_attributes(globals(), powerline_module, replaces) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'path'))) def tearDownModule(): - global replaces - replaces = swap_attributes(globals(), powerline_module, replaces) sys.path.pop(0)